web-dev-qa-db-ja.com

Javaクロスサイトスクリプティングを防ぐためのベストプラクティス

OWASPのトップ10の脆弱性を確認したところ、クロスサイトスクリプティングが注意を払わなければならないことがわかりました。推奨される解決策はほとんどありませんでした。入力でXSSを検出したり、出力をエンコードしたりするために「ブラックリスト」検証を使用しないでください。ほんの数文字(<および>およびscriptなどの他の類似の文字またはフレーズは弱く、攻撃に成功しています。未チェックの“<b>”タグは、一部のコンテキストでは安全ではありません。 XSSには、ブラックリスト検証のバイパスを容易にする驚くべき数のバリアントがあります。別の解決策は、強力な出力エンコーディングと言いました。レンダリングする前に、すべてのユーザー指定データが適切にエンティティエンコード(出力メカニズムに応じてHTMLまたはXML)されていることを確認してください。それでは、クロスサイトスクリプティングを防止して入力を検証および置換するか、出力をエンコードするのを防ぐ最良の方法はどれですか?

32
Hoe Chin

通常の慣行は、再表示中/ JSPでuser-controlledデータをHTMLエスケープすることです。処理中サーブレットで送信されたデータまたは格納中DBの場合、JSPでは [〜#〜] jstl [〜#〜] を使用できます(インストールするには、 jstl-1.2.jar/WEB-INF/libにドロップします)- <c:out> タグまたは fn:escapeXml この機能。

<%@ taglib uri="http://Java.Sun.com/jsp/jstl/core" prefix="c" %>
...
<p>Welcome <c:out value="${user.name}" /></p>

そして

<%@ taglib uri="http://Java.Sun.com/jsp/jstl/functions" prefix="fn" %>
...
<input name="username" value="${fn:escapeXml(param.username)}">

それでおしまい。ブラックリストは必要ありません。ユーザーが制御するデータは、HTTPリクエストによって受信されるeverythingを対象とすることに注意してください。リクエストパラメータ、ボディ、およびヘッダー(!!)です。

送信されたデータの処理中および/またはDBへの保存中にHTMLエスケープすると、ビジネスコード全体および/またはデータベース全体に広がります。これはメンテナンスの問題であり、異なる場所で行うとダブルエスケープ以上のリスクがあります(たとえば、&&amp;amp;ではなく&amp;になるため、エンドユーザーは文字通り&amp;ではなく&を表示します。ビジネスコードとDBはXSSに対して敏感ではありません。ビューのみです。ビュー内ですぐそこのみをエスケープする必要があります。

こちらもご覧ください:

41
BalusC

両方を使う。実際、出力エンコードの使用と入力検証の使用例として、 OWASP XSS Prevention cheat sheet のようなガイドを参照してください。

入力検証は、特定の場合に出力エンコーディングに依存できない場合に役立ちます。たとえば、URL自体をエンコードするよりも、URLに表示される入力を検証する方が適切です(Apacheは、URLエンコードされたURLを提供しません)。または、さらに言えば、JavaScript式に表示される入力を検証します。

最終的には、単純な経験則が役立ちます-ユーザー入力を十分に信用していない場合、または特定のソースが出力エンコードにもかかわらずXSS攻撃を引き起こす可能性があると疑われる場合は、ホワイトリストに対して検証します。

OWASP ESAPI ソースライブラリを見て、出力エンコーダーと入力バリデーターがセキュリティライブラリに書き込まれる方法を確認してください。

6
Vineet Reynolds

私の好みは、すべての非英数字をHTML数字エンティティとしてエンコードすることです。ほとんどの場合、すべての攻撃が非アルフネリック文字(<、 "など)を必要とするわけではないので、これにより、危険な出力の大部分が排除されるはずです。

形式は&#N;です。Nは文字の数値です(文字をintにキャストし、文字列と連結して10進数値を取得できます)。例えば:

 // Java-ish pseudocode 
 StringBuffer safestrbuf = new StringBuffer(string.length()* 4); 
 foreach(char c:string.split()){
 if(Character.isAlphaNumeric(c))safestrbuf.append(c); 
 else safestrbuf.append( "" +(int)symbol); 

また、ブラウザーに出力する直前にエンコードしていることを確認する必要があります。これは、二重エンコードを回避するため、またはHTMLのエンコードを別の場所に送信するためです。

0
atk