Javascriptのセキュリティを考える(脆弱性攻撃の防止とAPI対策)
Javascriptは万能で高速なWEB開発に必須の言語ですが、どうしてもセキュリティ面の脆弱性があります。
Javascriptおよびライブラリに脆弱性がないかはセキュリティ診断ツールを利用しましょう。
コードの書き方次第で攻撃者の侵入をある程度防ぐ事ができます。そしてプロジェクトニーズに応じたAPIのセキュリティ対策を取る事です。
JavaScriptはWEB開発の基盤言語
ブラウザサイドのスクリプト言語であるJavaScriptの人気が最近ますます高まっています。
JavaScriptは超高速の応答時間を実現しつつインタラクティブな要素も持っています。
ユーザーを引き付けるWEBアプリケーション開発の基盤として、Javascriptは頻繁に使われているのですね。
セキュリティ面で難題を抱えるJavascript
ただしことセキュリティの面においては、JavaScriptを避けようという考えを持つのも事実です。
以前まで悪意ある第三者がWEBサイトユーザーを操作する手段の一つとして、JavaScriptが簡単に悪用されていたためです。
本記事では一般的なJavaScriptによる脆弱性攻撃、そしてこれらがもたらすリスク、そしてWEBサイトを安全に保つセキュリティ方法をご紹介します。
JavaScriptが受ける脆弱性攻撃
最も一般的な脆弱性攻撃としては以下が代表例でしょう
クロスサイトスクリプティング(XSS)
クロスサイトリクエストフォージェリ(CSRF)
サーバーサイドJavaScriptインジェクション
さらにJavascriptは元々、クライアントサイドにおける根本的なロジックの問題を抱えています。
XSS攻撃
クロスサイトスクリプティング(XSS)は、最も一般的なブラウザ側の脆弱性を突いた攻撃の1つです。
このタイプの攻撃は、攻撃者が悪意のあるコードを正規のアプリケーションが持つ脆弱な部分に挿入する事で発生します。
攻撃者はJavaScriptとHTMLを操作して、悪意のあるコードまたはスクリプトをユーザーに植え付けるのです。
エンドユーザーの端末で悪意スクリプトを設置・実行するため、脆弱なアプリケーションまたはWEBサイト自体が「媒体」として使用されるのです。
CSRF攻撃
クロスサイトリクエストフォージェリ(CSRF)攻撃とは、セッションCookieをハイジャックして、ユーザーのブラウザセッションを乗っ取る或いは偽装する攻撃です。
CSRF攻撃はユーザーの意図しない悪意のあるアクションを実行させたり、WEBサイトで不正なアクションを実行させたりする可能性があります。
この例ではセッションCookie自体が、攻撃者が正当なユーザーになりすますための「手段」になっています。
サーバーサイドJavaScriptインジェクション
サーバーサイドJavaScriptインジェクションは新しいタイプのJavaScript脆弱性攻撃です。
主にNode.jsアプリとNoSQLを対象としています。
XSS攻撃がエンドユーザーのWEBブラウザで実行されるのに対し、この攻撃はサーバーサイドを対象とした攻撃となります。
サーバー側に甚大な被害を及ぼす攻撃
サーバーレベルで実行される攻撃のため、WEBサイトにより大きな影響を与える可能性があります。
このタイプは、攻撃者がWEBサーバーに悪意のあるバイナリファイルをアップロードして実行させようと試みます。
攻撃者が脆弱なコードを利用してサーバー攻撃を仕掛けるため、脆弱コード自体が「媒体」になっていると言えます。
クライアント側のロジックの問題
Javascriptはクライアント側で安全な処理をしようとすればする程、ブラウザをハッキングしている攻撃者側に筒抜けになる傾向にあります。
例えばAPIキーがクライアント側のJavaScriptに直接記述される仕様だと、これは攻撃者に対して脆弱になる事を示します。
ですのでコーディング自体が貧弱だと、攻撃者にとってWEBサイトとそのユーザーが絶好の「カモ」にされてしまうのです。
このようにJavascriptは根本的なセキュリティの問題を抱えているのですね。
脆弱性が抱えるリスク
上記のようなJavaScriptの脆弱性が存在する場合、サイト自体が攻撃者に対して脆弱な状態になっています。
ハッキングされたWEBサイトは、もちろんそのブランドに傷がつきます。
さらにWEBサイトを復旧する間は閲覧する事ができなくなる訳ですから、その間が長いほどユーザーからの不信感が増すでしょう。
つまりビジネス的にもお金や生産性、そして将来の上顧客なりえる可能性を秘めたユーザーの信頼を失ってしまうのです。
予算の都合で予見を無視した結果である場合も
安全でないJavaScriptと不適切なコーディングは、コストダウンの結果もたらされたものの可能性が高いとされています。
セキュリティリスクを前もって指摘されておきながら、予算を削るために対応をしなかった事が原因の被害事例もたくさんあるのです。
JavaScriptセキュリティ診断ツール
外部からWEBサイト(またはWEBアプリケーション)を調査して、インジェクションや攻撃に対して脆弱かどうかを判断するのに役立ついくつかのセキュリティツールがあります。
これらのツールを使い始める前に、前もって侵入テストポリシーを確認してくださいね。
以下では、主要な脆弱性スキャンツールのいくつかについて説明します。
ZAP
ZAP(Zed Attack Proxy)は、セキュリティ機関OWASPによって開発され、幅広い脆弱性についてWEBサイトを簡単にスキャンする機能を提供します。
直感的なインターフェースのため幅広いユーザーレベルで使用できますし、プロジェクトニーズに合わせて幅広くカスタマイズできます。
リンク:ZAP
Grabber
GrabberはWEBサイトをスキャンして、SQLインジェクションやXSSからAJAXテスト、ファイルインクルードまでの脆弱性を検出できます。
他のツールよりも速度が遅い傾向にあるため、小さなWEBサイトまたはWEBアプリケーションでの使用を推奨します。
アプリのスキャンなどによく使われます。
Wapiti
Wapitiを使用すると、ユーザーはGETとPOSTの両方のHTTPリクエストを使用して、攻撃と注入ベクトルをテストできます。
ファイル開示とファイルインクルージョン、XSS、Apacheの貧弱なサーバー構成などがあれば検出します。
これはコマンドラインから実行されるよりも高度なツールとなっています。
リンク:Wapiti
GoogleChrome Light house
GoogleChromeの拡張機能である「Lighthouse」を使ってWEBサイトを診断する事ができます。
既知のセキュリティの脆弱性があるフロントエンドJavaScriptライブラリがあれば警告を表示します。
Chromeのライブラリ検出機能を実行したり、検出されたライブラリのリストをsnykの脆弱性DBと照合する事で診断します。
JavaScriptコードを保護する方法
最も一般的な攻撃ベクトルと脆弱性を知ることは、WEBサイトを保護するための重要なステップです。
ただしこれらの問題を回避するために従うべき、JavaScript開発におけるセキュアな書き方があります。
コードが常に安全である事は保証できませんが、以下の手順を使えば本質的に多くの攻撃を防ぐことができます。
コード挿入を防ぐ
例えば次のようなコードの確認をする必要があったとします。
<a name="makelink-1"></a> function makeLink(linkTextHTML, url) { return '<a href="${ url }">${ linkTextHTML }</a>'; }
もし上記の状態で下記のようなケースの場合はどうなるでしょう。
const x = '<script>alert(1)</script>'; const y = 'javascript:alert(1)'; console.log(makeLink(x, y)); 上記はこうなります。 <a href="javascript:alert(1)"><script>alert(1)</script></a>
単にリンクURLを作るだけの機能のはずが、スクリプト実行されるコードになってしまいました。
代入される文字には(コード自体)も含まれる危険性がある事を指しています。
その事に対し何も制御をしていないと、プログラムはそのまま受け入れてしまう弱点があるのです。
コードを無効化する加工をする事
単純に文字列が入る事だけを想定する事無く、代入される文字列からコードとなる記号を全て無効化するなどの工夫が必要です。
まあこの辺りは当たり前の事ではありますね。
eval関数の使用を避ける
開発者はeval関数を使用してテキストをコードとして実行しますが、これは基本的には危険な行為です。
ほとんどの場合これらの機能は別のもので代用ができます。可能な限りeval()を使わずに別の関数に置き換えましょう。
CORSヘッダーを使用する
CORS(クロスオリジンリソースシェアリング)は、WEBサイトのリソースを参照できるソースを定義するために設定できるヘッダーです。
CORSはブラウザがオリジン(HTMLを読み込んだ実サーバー)以外のサーバーからデータを取得する仕組みです。各WEBブラウザにはクロスドメイン通信を拒否する仕組みが実装されているため、CORSを設定しないと基本的には別ドメインのデータを読み込む事はできません。
これはクロスサイトスクリプティングを防止するためです。
WEBサイトAのお問い合わせフォームを利用しているのにWEBサイトBに向けて個人情報データが送信される、などの行為を防ぎます。
これらのルールはNginxなら構成ファイル、Apacheならば.htaccessファイルに配置できます。
Access-Control-Allow-Origin: https://llpeg.info
これによりリソースの参照先を限定する事ができるので、外部からの参照を行う事はできなくなります。
コンテンツセキュリティポリシーヘッダーを使用する
コンテンツセキュリティポリシーもCORS同様、Nginxなら構成ファイル、Apacheならば.htaccessファイルで設定できるヘッダーです。
このポリシーではJavaScript、CSS、font、iframe、mediaなど許可をするリソースを定義できます。
ヘッダー定義例
Content-Security-Policy: default-src: 'self'; script-src: https://api.google.com;
上記のポリシーの説明
デフォルトでは全てのソースがホスト/WEBサイト自体
JavaScriptの場合はapi.google.comも受け入れる
それ以外の全ての外部ソースを拒否
上記のような意味になります。
CORSやポリシーの書き方については割愛しますので別途お調べ下さい。
SSL/HTTPSを使用する
SSL(Secure Sockets Layer)は、ユーザーがWEBサイトとやり取りする際の送信データを暗号化する方法です。
元々ユーザーがデータを入力する場面(ログイン、お問い合わせ送信、注文、コメント入力)は、SSLで保護する事が大切とされていました。
現在はhttps通信がSEO対策のランキング要因になる事がGoogleからアナウンスされていますので、ページ保護以外の観点からもSSLは必須項目とされています。
JavaScriptで安全なCookieを設定する方法
Cookie情報は一番悪用されやすいユーザー足跡情報になります。
ユーザー情報を確実に暗号化するもう1つの方法は、Cookieの使用を制限してWEBページを保護する事です。
つまりWEBページがSSL(https)を使用していない場合には、Cookieが送信されないようにするのです。
Cookieの送信を操作するには次の属性タイプが使用できます。
Cookie属性タイプ
Secure…Cookieは暗号化されたチャネルでのみ送信(https通信)
HttpOnly…ローカルスクリプトによるCookieの読み取りを許可しない
Domain…ドメイン設定を再確認
Path…パス設定を再確認
Expires…ユーザーエージェントを解析するか、有効期限を選択する方法を決定
例えばCookieを「Secure」(https経由)でのみ送信するよう指定するには、次の構文になります。
document.cookie = "tagname = test;secure";
JavaScript APIのセキュリティ
JavaScript APIシステムは、JSONファイルが実行されるとクライアント側に返される事もあり、セキュリティ対策に苦労すると言われています。
API内部の動作の一部が、注意深く見れば外部から盗み見する事ができる状態であるためです。
APIで機密情報を送信する際のセキュリティオプションを活用する必要があります。
JavaScript APIシステムにおいて使用するセキュリティおよび認証システムは、そのプロジェクトのニーズによって異ってきます。
様々なニーズにマッチしたAPIセキュリティオプションを一部ご紹介します。
秘密鍵によるAPIキーの保護
最も一般的に使用されるオプションは、「APIアクセスと秘密鍵のペア」を設定する方法です。鍵管理方式ですね。
対応する鍵のみがAPIへのアクセスを許可する様に、個々の秘密鍵を各エンドユーザーに割り当てます。
アクセスキーと秘密鍵のペアが一致しない場合、APIへのアクセスを取消・拒否する訳です。
大量ユーザ―を抱える大企業が採用
GoogleやFacebookのような企業は、一般的にこの方法をエンドユーザーの検証に使用していますね。
Facebookは主に各ユーザーに割り当てられた秘密鍵に依存していますが、GoogleはOAuthを介して実際のサーバーで秘密鍵を使用する傾向があります。
この様な鍵による管理オプションは、広大で不明瞭な多数のユーザーベースを持つ組織には最適な方法でしょう。
特定のIP範囲へのアクセスを制限する
これはAPIが特定のグループまたは建物内でのみ使用される場合に有効です。
許可されたIPアドレスのIPホワイトリストを維持する事で、APIのセキュリティが管理できます。
ただしIPアドレスが頻繁に変更される傾向があると、この機能は面倒になる可能性があります。
環境が頻繁に変更されない既知のユーザーによる限定されたグループ間での利用に最適です。
IPアドレスの利用制限
APIセキュリティにおいてはIPアドレスを利用制限する事も使いにくい面がありますが有効です。
そのため1日に限られた回数しかAPIにアクセスできません。
このタイプのシステムを実装する場合、きちんとユーザーの使用統計データを事前に収集しておくべきでしょう。
APIを普通に利用するユーザーと、それを悪用する攻撃者との間に利用回数における「明確な違い」があるかどうかを調べるのです。
まとめ
Javascriptは万能で高速なWEB開発に必須の言語ですが、どうしてもセキュリティ面の脆弱性があります。
Javascriptおよびライブラリに脆弱性がないかはセキュリティ診断ツールを利用しましょう。
コードの書き方次第で攻撃者の侵入をある程度防ぐ事ができます。そしてプロジェクトニーズに応じたAPIのセキュリティ対策を取る事です。