コロナ下での落ち込みから立ち直るまで。
今回はコロナ下で入職した職場と馬が合わず転職し、 受託先とうまくいかず、さらに転職をし、昨年秋からお世話になっている職場で「コミュニケーションについて思い出す」事をメインにまとめます。
2019.XX(夏)
JavaでWebアプリのコードを書く職場に転職。 <<同僚・バイザーとの折り合い>>
2020.XX(春)
Kotlinを学んだりテストコードを修正するなどする。(このへんで自身のエンジニアとしての死をうっすら自覚する) 転職活動開始。
2020.05
某受託先にてRailsのフリーランスとして入職。 <<経営者兼技術者との折り合い>>
2020.10
某非営利組織に教育&コードボランティアとして参加。 現在のヘルステックアプリ開発プロジェクトにジョイン。 <<ディレクターとの折り合い>>
①同僚・バイザーとの折り合い
Rails, Rubyだけではなく型付きの言語で現場のコードを書きたい、と思ったためジョインした職場での出来事。 実際Javaに関してはオブジェクト一つとってもRubyとは書き込む量が段違いだったし、腰を据えてコードを読みたいと思える現場だった。
ただし、要件定義〜実装〜デバッグみたいに開発スタイルがあるわけではなく、割とアジャイルみたいな動きをしていたと思う。正直その時の自分にとっては、開発に意識を割くリソース:開発外に意識を割くリソース=7:3くらいでやっていきたかったけど、それが難しい状況だった。
開発外に意識を割くことを極力減らしたくて、開発フローを確立させて行きたかったけれども、上記のような意図を周囲に伝えきれず、「開発者なのになぜコードを書くことを優先しないのか?」という発言を当時の同僚にさせてしまった。 とにかくハンパなく気が散っていた。
とはいえ同僚に干渉されるということは、個人的にまあまあストレスのある出来事で、次第にそれがバイザーとの関係性も悪くしていった。 (立場・理由を考えて、納得感の行く干渉であれば歓迎するというスタンスではあった)
無事に「不必要に仕事のやり方に干渉されて腹が立つ」という不満だけが伝わり、私の人格面におおいにマイナスの評価を抱いたようだった。(チームメンバーを尊重出来てナイ!)面談の回数も自然と遠巻きになっていった。
②経営者兼技術者との折り合い
前述の職場でKotlinでバッチを書く部署に移動になり、それはそれで楽しいと思っていた。 ただ技術の知識面については、悔しいことに「大量のデータをさばく経験もなく、型言語の扱いに習熟しているかと言われると怪しい状態」だった。(この時入職して半年)
リモートで勤務が始まったが、なにをがんばっても「たかがエンジニア業はじめて数年の人間がままごとをやっている」みたいな扱いをされていた。LTをするとマサカリではなく罵声が飛んでくる。 やる気も死んでいた。
とにかくアプリのコードをたくさん書きたくなって、Railsを書く仕事を探し始めた。
運良くマッチングした受託開発の会社でいくらかRailsのコードを書いたが、これがまたすごかった。 モデルが細分化され、今思い返せば継ぎ足されている秘伝のタレのごとしだったと思う。 フロントエンドもそうだったけど、少しの変更がすべての破滅を招く。
なつかしのCoffeeScriptと対面し、現実を受け入れた後で、フロントエンド側のリファクタリングからはじめようと心を入れ替えた。
方向性を打ち合わせして決めて、最初に出したプルリクでCSSで書いた決め打ちのpxについてコメントを求めてくる人間がいた。
話は変わるが、個人的にCSSで決め打ちをするのは、(何がとは言わないが)基本的にクソだと思う。
ここで注意したいのは、レビューの際にするコメントについては、建設的な展開をある程度予想して書くことである。 コードはクソだが、品質を担保しなければそれ以上のクソ扱いをされるこの現場では、このようなマウンティングが発生する。
私はこの現場で何も学ばなかった。受託って大変すね。
上記の諍いを見ていた現役のエンジニア兼取締役にあれこれ言われた気がするが、なんだか忘れた。 覚えているのは、お前の生産性が低いから金を出したくないみたいなことだったかな。 確かに工学系の学生を、アプリのコードを書かせてこき使うのは合理的だし、そいつらに比べると使いづらい従業員なのはもっともだな。まあフリーランスやししゃーない。という感想を抱く。(この人については、人を育てるみたいな感性は歴代バイザーの中で最も低かったと感じた) ここで経営者的にどう思ったのか、みたいな考えの側面を身につける。 ついでにふてぶてしさと面の皮も厚くなった。
③ディレクターとの折り合い
現在はまたRailsのコードを書いている。ORマッパーや、諸兄の活躍のおかげで隠蔽されまくった愉快なミドルウェアたちとのお付き合いだけでなく、エラー監視の仕組みの導入だったり、AWS各種の使い方を学んだり、以前よりは基底に近い分野で仕事をさせていただいている。やってみたいことは相談の上、どんどんさせてもらえる。ありがたい。
もっと勤務中は開発に時間を割きたい。そう思うことで発生するのは①に親しい出来事で、「開発部署以外とのコミュニケーションロスを避けたい・コミュニケーションする時間自体を低減させたい」みたいなことだった。
とくに要件定義、できれば基本設計についても、自分の仕事ではなく誰かの仕事にしたい。(欲しい物くらい明確に頼んでくれ、あわよくば他人にIN/OUTの責任を持って欲しいと思ってしまうのは私だけ?)
そのようなことは当然叶わないので、地道に打ち合わせをし、用件を拾うが「なにをどれだけいつまで」がビジネスサイドと決着しないこともしばしばある。
各々がいろいろを忘れることもあるので、プライドは捨てて、アホみたいに確認を取っている。 話が進むだけありがたいしもう私はアホでいい。
まとめ
アホを自覚したので、それを踏まえてどう生き残るかを今後考える。 面の皮は厚いし、仕事を始めた当初の純粋さのかけらもなくなったが、今が一番楽しい。
GoogleAnalyticsAPIについての覚書
アクセス数とセッション数を管理画面から見れるようにしたいよ〜という依頼があったので。 GCPでAPIとサービス > 認証情報でサービスアカウントを作成 サービスアカウントで秘密鍵を作っておく(今回はjson形式) jsonはS3に設置する
APIを叩くtaskをこさえます
認証の抜粋
def authorize_with_view_ids # S3::ClientServiceをincludeしているプロジェクト独自のモジュール client = S3::ClientService.execute json_file = client.get_object(:bucket => [バケット名], :key => [S3にあるjsonのkey]).body @analytics = Google::Apis::AnalyticsreportingV4::AnalyticsReportingService.new credentials = Google::Auth::ServiceAccountCredentials.make_creds(json_key_io: json_file) credentials.scope = 'https://www.googleapis.com/auth/analytics.readonly' @analytics.authorization = credentials.fetch_access_token!({})['access_token'] end
APIを叩く部分の抜粋
request_product = Google::Apis::AnalyticsreportingV4::GetReportsRequest.new({ report_requests: [ { metric: [{ expession: 'ga:1dayUsers' }], dimensions: [{ name: 'ga:date' }], date_ranges: [{ start_date: start_date, end_date: end_date }], view_id: "ga:#{PRODUCT_VIEW_ID}" } ]})
metricsの定義はこちらで調べることができます。 data_rangesはyyyy-mm-dd HH:mm:ssで投げればOK。
PRODUCT_VIEW_IDはGoogleAnalyticsで割り当てられているビューIDのことです。GoogleAnalyticsの画面で設定していきましょう。 アカウントユーザーの管理にサービスアカウントを追加してください。
サービスアカウントは前の手順で発行したメールアドレスのことです。(@-******.iam.gserviceaccount.com) ここで権限がないままjsonの認証情報を持ってAPIを叩くと参照権限がないよと怒られます。
長いREADMEを軽く読み飛ばして、Githubのsampleコードから試していったら非常に時間がかかってしまった。
メンターとしてCorderDojoに参加しました
また更新頻度が落ちてしまいました>< 最近はまたRailsを書き始めていて、jsや型のことを忘れ始めています😨w
8月末から、CorderDojoの活動に参加させていただいています。
Corder Dojoとは
Corder Dojoとは
CoderDojo は7〜17歳の子どもを対象にしたプログラミング道場です。2011年にアイルランドで始まり、世界では110カ国・2,000の道場、日本では全国に218以上の道場があります。 CoderDojo では統一したカリキュラムは採用していません。代わりに必要な時にメンターが相談に乗ったり、子ども同士で学び合うことを推奨しています。これは受動的に何かを教わることよりも、作りながら主体的に学ぶことに価値があると考えているからです。
参加のきっかけ
この活動に参加したきっかけは、兼ねてよりプログラミング教育に興味があり、業務ではなかなかメンターとして立ち回る機会が得られなかった為、業外でやってみようと思ったからです。
正直に言って、一番最初に打ち合わせをした時にメンターの方々のプログラムの組む速さであったり、教え方のうまさに驚きました。 また、この速度で小学生くらいのニンジャ(ドージョーの利用者)は理解が追いつくか心配でもありました。
小学生にいきなりプログラミングしてもらうことを難しいと感じた理由
なぜなら、まずプログラミングをする上で具体的な理解が必要になります。(基本だと、変数や関数の概念)
やりたいことを実現する上で、具体的な指示をプログラムに出していかなければならないので、ここは必須です。 また、その理解を持ち、抽象的な理解をできて初めて応用的な処理を書いていくことができます。 例えば、何かの処理を写経して動かした後、似ているが少し違う処理を書きたい時に前回の内容を生かしつつ、別の処理も加えていく必要があります。
ドージョーで採用されているScratchは、上記の流れを幾度となく必要とします。 Scratchを触った感想として、正直表現がGUIに寄っただけで、Webアプリで必要になる言語とは大差がないと思いました。 このような概念を(特に初めて参加する)小学生に伝えられる自信がなかったんです。
しかし、実際にドージョーの活動に参加してみて、その不安は軽減されました。
Corder Dojo当日の話
その日はScratchでUFOキャッチャーを作る会になりました。 モブプログラミングをオンラインで行う時点で、私は難しさを感じていました。
ベテランのメンターがモデレータとなり、ニンジャに作りたいもののアイデアを募りました。 それから、実際の処理を作る上で「ここからどうなればいいと思う?」といったような質問をニンジャに投げかけることで、 具体的な挙動を考えるまでもなく、モブプロに参加することができます。
実際は「当たり判定を作って、そこに景品が触れるイベントを作る」のような、フラグの概念をその場で回答して見せていました^^; 小学生恐るべしww
その場でデバッグをして、プログラムを改良し提出することもこなして見せていました。 (この子たちはプログラミングの概念を理解しつつ、作ることを心から楽しんでいる様子でした。)
作りたいものが出来上がると、普段自分が作っているものの発表の時間になります。
私はファシリテーター的なポジションで参加していました。 チャットでコミュニケーションしつつ、まんべんなく、発言したい子が注目されるように呼びかけなどを行いました。
当然、時間が限られているので、上記を強制すると、まだまだ話し足りない様子の子も見られますが、 他の子の発表に耳を傾け、「すごい!」と称賛したり、Scratchのフォロー機能を使ってコミュニケーションを取る様子が見られました。
大人より大人びた対応をしています😅 オンライン特有の限られた人が音声を占有してしまう特性に対して、チャットを使って積極的に参加しようとしていました。
Dojoに参加するニンジャの印象
以上のように、元々プログラミングスキルが高く、建設的な話し合いができる子たちの会に参加しました。 まとめると、以下の3つのような印象を持ちました。
- 思ったよりもやりたいことを発言できる子がいる
- 発言が具体的であればあるほど、プログラミングも好んで進めている
- 対照的に発言やチャットはせず、見ている様子の子がいる
どういうメンターでありたいか
私としては、3番目の子どもたちについて関わりを持ちたいと思っています。 個人的に試したいと思っているのは、ある程度概念を優しい言葉で伝えるようなマニュアルを作成し、Webアプリを作ってもらう経験です。 性格的に人と共有するのは苦手だが、まずはやってみたい子に対して達成感や自信になるような経験を提供できればと思っています。
React.jsでSPAを作った後にテストを書いた(散文)
React.jsの練習がてら、某プロダクトのコピーSPAを作りました。 Three.jsでぬるぬる動く。 https://ixap2i.github.io/try-react-app/
ほとんどメインの動画部分や素材に力を入れていた為、力の配分が素材やCSS多めになってしまった…
1週間くらいで一気に作り上げたので、人に見せたところ「ちょっとCSSの設計が…?」とのような感想もいただいてしまい、見直す目的でちょっとテストを書いています。
よかったことは、htmlタグの階層や命名を見直せたところや、無駄なCSSがあったのを消せたところかなあ。 sectionタグは入れ子にして使ってもよかった
静的なコンテンツしか今回は扱っていないので…APIやデータオブジェクトのテストは書いてない。 反省としては、この要素やコンテンツは存在しているか?という内容の浅いテストになってしまった。
(セットアップに思ったよりてこずったんだもの…←これはテストコードがライブラリを参照する際に起こるエラーで、テスト用のモックアップを差し込めば解決しました。)
Jestを使ってみたけど、jest.comfig.jsとsetup-jest.jsを別々に作る必要がある。 前者は特定のjsファイルがどの階層のモックアップを参照するか指定できたり、モジュールの拡張子などを指定できたりする。よく知っている形式の環境設定ファイル。 後者はわざわざ別に作って、"setupFilesAfterEnv"というプロパティでテストをするときに使用するライブラリを書き連ねている。
import '@testing-library/jest-dom' import '@testing-library/dom' import '@testing-library/jest-dom/extend-expect'; import 'mutationobserver-shim';
setup-jest.js↑
こんな感じに。これがないとtoContainElementなどのアサーションする関数を呼べないのだ。もちろん個別にファイルの中でimportすれば呼べるけど、書くのが面倒なのでまとめておくタイプにした。
はじめてのスクレイピング アプリでOSの依存性やCORSなどに殴られた話。
早いもので、盛夏の真っ只中です。後5ヶ月もしたら29回目の紅白歌合戦。 ここ数ヶ月に渡って、TypeScript, Angular.js, Node.js, AWS…などなど、前の現場の復習も兼ねて触ったりしていました。
シングルページアプリケーション www.oreilly.co.jp
を読んだ3年前、何がどうなっているかわからないうちに手を動かしている部分もありましたが、 今回はもう少し発展的なことができたかな…テスト書いてないけど…
今回作ったもの
バイクが大好きですが、横断的に車両の情報を表示しているWebページがなかった気がしたので、 バイク情報の表示 + 内容をDBに取り込んで検索 できる物を作ってみました。もう自己満足です。 今の仕様では前者だけの要件を満たしていますが、まずはローカルでの開発〜デプロイまでのいろいろをメモしていきます。
今回作る上でやってみたかったこと
バックエンドJSと、フロントエンドはAngularで書きたかった。です。
フロントはVueを使うことも検討しましたが、よりサービスロジックに近いこと + オブジェクトを独自のデータ型で定義し、扱うことが主流になっているAngularにしました。 (Vueでも好きなオブジェクト型は作れるが、構成に頭を使うことと、Component単位の実装をして、再利用について全て一緒にやっていたら頭がおかしくなりそうだった)
バックエンドJSは最近流行っているから…、Nodeを書きたい気持ちになった。JavaScriptができることの可能性をバックエンドまで体験したかった。という理由です。
苦労した点
はじめてのEC2インスタンスで環境構築
AWSを触るのはほぼほぼはじめて。(前職ではSSL証明書の更新をやらせてもらったくらい)
インフラって本当に抽象的というか、実際に触らないと実感としてわかないところが多い。なので前職ではむりくり理由をつけて触らせてもらったw自分で物作るときはホスティングサービスにお世話になってたからね…
マシンタイプの選定も、よくわからずどうせ拡張するからね!って理由でAmazon Linux2のt2.micro(メモリ1GBw)を選択したけど、これが後々の環境構築に大きく響くことになった…ここに関しては調査不足が否めない。
まっさらなOSにいろいろインストールするのは比較的脳死で行ってたけど、後々CentOSに切り替えてからsudo yum whatprovidesコマンドの存在を崇めることになる。平たく言うとrpmライブラリがなにに依存して動いているかがわかる。今足りないものについても教えてくれる。rpmってなに
スクレイピング してくれるライブラリ(puppteener)のlaunch error
ものごっつ便利なスクレイピング アプリがあると聞いて、まず導入してみた。 比較的最近Nodeでの開発事例があることと、READMEがしっかりしてたからまず使ってみた。Dockerの上からでも動く。
OS別の動かし方も載っている。 が、EC2上で動かすときにUnhandledPromiseRejectionWarning: Error: Failed to launch chrome!と出る。 node/node_modules/puppeteer/.local-chromium/linux-*****/chrome-linux/chromeとか出ているから、chromeが参照できなくて怒ってるんだね。権限周りを散々疑ったり、引数にわざわざ上記のパスを書いてみたりしたけれど、この段階ではうまく解決できなかった。
OSとライブラリの依存性
上でもちょっと触れているけど、最初はAmazon Linux2上でpuppteenerを動かしてた。上に書いてあるようなエラーにぶち当たって、思い切って新しいインスタンスを立ててみることにした。(なけなしの銭を投げ打って。w) これは正解だったみたいで、前のOSでは見つけきれなかったパッケージなどをうまくインストールすることができた。 これによってUnhandledPromiseRejectionWarning: Error: Failed to launch chrome!は見えなくなったし、puppteenerが動いているAPIのエンドポイントで真っ白なページを眺めることもなくなった。w
わかりづらいけど、あるバイク販売店のHPのhtmlを丸ごとリクエストして、そこから必要なDOMから文字列を抜き出してる。
フロントエンドで<td>
を挿入するように整形しているはずだけど、なぜか数珠つなぎになってるw直さなくては。
最終的にスペックは t2.medium Red Hat Enterprise Linux にした。
必要だったやつ
sudo yum install alsa-lib.x86_64 atk.x86_64 cups-libs.x86_64 gtk3.x86_64 ipa-gothic-fonts sudo yum install libXcomposite.x86_64 libXcursor.x86_64 libXdamage.x86_64 libXext.x86_64 libXi.x86_64 libXrandr.x86_64 libXScrnSaver.x86_64 libXtst.x86_64 pango.x86_64 xorg-x11-fonts-100dpi xorg-x11-fonts-75dpi xorg-x11-fonts-cyrillic xorg-x11-fonts-misc xorg-x11-fonts-Type1 xorg-x11-utils
lddコマンドで調べてから、また足りないライブラリのためにwhatprovidesで調べたりした。
ldd /node_modules/puppeteer/.local-chromium/linux-756035/chrome-linux/chrome linux-vdso.so.1 (0x00007fff041e2000) libdl.so.2 => /lib64/libdl.so.2 (0x00007f1ef9dd3000) … libnspr4.so => /lib64/libnspr4.so (0x00007f1ef70ac000) libatk-1.0.so.0 => not found libatk-bridge-2.0.so.0 => not found libcups.so.2 => not found libdbus-1.so.3 => /lib64/libdbus-1.so.3 (0x00007f1ef6e58000) libXss.so.1 => /lib64/libXss.so.1 (0x00007f1ef6c54000) libgio-2.0.so.0 => /lib64/libgio-2.0.so.0 (0x00007f1ef68ab000) libexpat.so.1 => /lib64/libexpat.so.1 (0x00007f1ef6670000) libXrandr.so.2 => /lib64/libXrandr.so.2 (0x00007f1ef6465000) libdrm.so.2 => not found libm.so.6 => /lib64/libm.so.6 (0x00007f1ef60e3000) libgbm.so.1 => not found libasound.so.2 => not found libpangocairo-1.0.so.0 => /lib64/libpangocairo-1.0.so.0 (0x00007f1ef5ed4000) libpango-1.0.so.0 => /lib64/libpango-1.0.so.0 (0x00007f1ef5c8d000) libcairo.so.2 => /lib64/libcairo.so.2 (0x00007f1ef596c000) libatspi.so.0 => not found libgtk-3.so.0 => not found libgdk-3.so.0 => not found libgdk_pixbuf-2.0.so.0 => not found …
CORSで殴られる
ローカルで開発して喜んでる人だったから、CORSに悩まされたの。(こういうことを生業としていた会社に勤めていながら、恥ずかしい) API側でヘッダーの設定の書き方がちょっと違ったのでしばらく悩んでた。
res.header('Access-Control-Allow-Origin', '*'); - res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); - res.header('Access-Control-Allow-Methods', 'OPTIONS, GET, POST, PUT, DELETE'); + res.header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token'); + res.header('Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS');
セキュリティグループの設定をうっかり忘れる
工程的には前の方だけど、インバウンドグループを設定し忘れるなんてこともあった。
次にやること(優先度順)
デザインをマシにする スマホで見れるようにする テストを書く ドメイン取る 機能の拡充
感想
express爆速。超便利。
プロジェクトのベース
Denoことはじめ
最近はQiitaをチェックする頻度が減っていたのですが、Nodeよりも強いjsが出たよと聞いて触らずにはいられませんでした。チュートリアルから読み取れた一部の内容を、めっちゃざっくりとまとめておきます。
※ちなみに私はNodeに関してはlocalhostでHello Worldしかしたことがありません。
何が"強い"かというと、
- 1つの実行ファイルで動作する(node_modulesは必要ない)
- Node.jsに比べてセキュア
- 依存性の書き方がシンプルになった
という点らしいです。
Deno自体は依存性なしでファイルを実行します。( 1つの実行ファイルで動作する)
コマンドをインストールすれば、即開始できます。 Shell (Mac, Linux):
curl -fsSL https://deno.land/x/install/install.sh | sh
ウェッブ上にあるファイルをシンプルに実行してみます。
deno run https://deno.land/std/examples/welcome.ts
https://deno.land/std/examples/welcome.tsにアクセスすると、ドキュメントページが迎えてくれます。
シンプルなHTTPリクエストをするアプリの例(セキュア)
例の通り下記のコマンドを叩くと、
deno run https://deno.land/std/examples/curl.ts https://example.com
エラーが出ます。
Download https://deno.land/std/examples/curl.ts Warning Implicitly using master branch https://deno.land/std/examples/curl.ts Compile https://deno.land/std/examples/curl.ts error: Uncaught PermissionDenied: network access to "https://example.com/", run again with the --allow-net flag at unwrapResponse ($deno$/ops/dispatch_json.ts:43:11) at Object.sendAsync ($deno$/ops/dispatch_json.ts:98:10) at async fetch ($deno$/web/fetch.ts:591:27) at async https://deno.land/std/examples/curl.ts:3:13
ここで私たちはプログラムに対して、ネットワークにアクセスするための特権を明示的にしておかなければなりません。
deno run --allow-net=example.com https://deno.land/std/examples/curl.ts https://example.com
--allow-netフラグはその役割を持っています。
DenoのAPIはDenoからグローバルに参照することができます。(依存性の書き方がシンプル)
APIは下記から参照することができます。
その他
ファイルの読み込み(Ex)
for (let i = 0; i < Deno.args.length; i++) { let filename = Deno.args[i]; let file = await Deno.open(filename); await Deno.copy(file, Deno.stdout); file.close(); }
これは仮にfilenameにファイルのパスが渡されていたとして、見ての通りファイルの内容が標準出力されます。
copy()はカーネル→ユーザーディレクトリ→カーネルの必要なコピーしかしていません。 ファイルからは同僚のメモリが読み出され、そのまま出力されます。これはDenoにおいてのI/O出力の普遍的な設計を表しています。
テストも書くことができます。
assertion utilitiesをimportするだけでそれが実現できます。 非同期関数についても用意があるようです。
Chrome Developer Tool向けのデバッガの用意もあります。
インストール後にinspectを有効にすると、localhost:4500にアクセスすることでログイン中のリポジトリのjsファイルが見れるようになっています(ちょっとゾワっとする) https://deno.land/manual/tools/debugger
感想
セキュリティ周りについていいお勉強になりそうだと思いました。 バックエンド色の強いチュートリアルが多かったので、今回はこれ以上深入りしないようにします^^;
Deno
を参照することでテストやAPIも呼べる点がシンプルで、実装しやすそう。
jsのフレームワークを勉強して、余裕が出てきそうだったらまた触りたいです。
JavaScriptのクロスサイトスクリプティングについて調べてみた
最近は「使うだけ」ではなく、設計レベルを目指してJavaScriptを勉強中です。 JavaScript本格入門を読んでいますが、jsの生い立ち、クロスブラウザの問題の背景を知ることができて、読み応えがある感じです。
そこで、「JSはセキュリティホールが多い」という誤解が一時期広まったと書いてありました。 これは、JSが動作するブラウザのセキュリティ対策が不完全だったことも相まって、JSの不人気の原因になってしまったようです。
記憶にも新しいニュースを載せておきます。 www.itmedia.co.jp
上記のようなモーダルを出す、という実装は、環境さえあれば手軽に実行できてしまうものなので、 それが誤解されてこのような事件に発展することもあるかと思います。
この機会に、理解があいまいだったJSで引き起こされる「クロスサイトスクリプティング」についてまとめていきます。
ゴール
初心者にクロスサイトスクリプティングがざっくり伝わる説明をする。
説明
*1クロスサイトスクリプティング(英: cross site scripting)とは、Webアプリケーションの脆弱性[1]もしくはそれを利用した攻撃。
①悪意のある人間がJSを使い、WebサイトのURLのパラメータやDOMを操作して、htmlを改ざんする。
②Webサイトを閲覧し、そのhtmlが表示されたユーザーが、別のページに誘導されてしまったり、不正に個人情報を抜き取られてしまう。
という流れです。この話は何度か聞いたことがありましたが、 では具体的にどういった実装が人々に不安をもたらしたり、害悪があるのかについて疑問でした。 いろんなパターンがあると思いますが、
モーダルを出して不安を煽る文句を見せる
モーダルを消すとリダイレクトする
といったパターンが多いようです。
そもそもなぜこのような操作がJSでできてしまうのか
実装によって異なりますが、
サーバサイドで不正なリクエストを受け取り、本来の実装とは異なるhtmlが返却される
という事象に集約されるようです。
不正なリクエストとは、不正な機能の載ったページをくださいという要求をサーバサイド側にするということです。 サーバサイドでは、このような悪用を防ぐ為に、不正なリクエストがあった時に安全なページを表示する為に工夫をすることができます。
エスケープ
ここではRubyを使ったエスケープという工夫を見ていきます。
例えば、攻撃者が悪意を持って
https://www.サイトURL?params=< script type= \"text/javascript" > alert("警告") < /script>
というコードをリクエストしたとします。(コピペで実行できないように、実際のものに少し手を加えてあります🙇♂️)
このままでは、htmlでparamsの値が表示される部分に、モーダルが出てきてしまいます。
これを、ブラウザがモーダルとして解釈しないように、ただの文字列にします。(プログラミングのコードではなく、文章にしてブラウザに伝える命令を変えてしまいます)
p CGI.escapeHTML('< script type= \"text/javascript">alert("警告") \')
#=> "<script type="text/javascript">alert("警告")</script>"
すると、#=>以降の文字列としてブラウザに解釈され、モーダルは出ずにコードだけがWebページに表示されるようになります。
Railsのビューヘルパー
上記はサーバサイド言語のRubyを使って説明していますが、アプリケーションを作るフレームワークでもすでに実装されています。 不正なURLにリダイレクトさせたくない時は、url_encodeも有効です。
ERB::Util - html_escape github.com
ActionView - FormTagHelper github.com
この部分は、erbでフォームを作るメソッドです。 フォーム内の文字がエスケープされるように処理が書かれています。
生い立ちを忘れずにメソッドの役割を理解する
今はこのような対策がWebアプリを作る際にすでに用意されているので、私個人として、使う時には意識をしない問題だったと思います。
これはあくまでブラウザが実装者の意図しない命令を解釈をしてしまうことでも引き起こされるので、今後の開発に役立てていこうと思います。
アイコン:
Icons made by Flat Icons, DinosoftLabs, and Freepik from www.flaticon.com
ありがとうございます。
(あまりJSの話ができなかった…)