
www.bugs_ja.htm Maven / Gradle / Ivy
Show all versions of findsecbugs-website Show documentation
Bug Patterns - Find Security Bugs
予測可能な擬似乱数生成器
セキュリティが重要な特定のコンテキストで使用された場合、予測可能な乱数の使用は脆弱性につながることがあります。例えば、その乱数を次のように用いた場合です。
- CSRF トークン
- パスワードリセットトークン (電子メールで送信された)
- その他の秘密の値
手っ取り早い解決策は java.util.Random の使用を java.security.SecureRandom などのより強固なものに置き換えてください。
脆弱なコード:
String generateSecretToken() {
Random r = new Random();
return Long.toHexString(r.nextLong());
}
解決策:
import org.apache.commons.codec.binary.Hex;
String generateSecretToken() {
SecureRandom secRandom = new SecureRandom();
byte[] result = new byte[32];
secRandom.nextBytes(result);
return Hex.encodeHexString(result);
}
参考文献
Cracking Random Number Generators - Part 1 (http://jazzy.id.au)
CERT: MSC02-J. Generate strong random numbers
CWE-330: Use of Insufficiently Random Values
Predicting Struts CSRF Token (Example of real-life vulnerability and exploitation)
信頼できないサーブレットパラメーター
サーブレットは様々なメソッドから GET と POST のパラメーターを読むことができます。得られた値は安全でないと考えるべきです。
以下のようなセンシティブな API に渡す前に、それらの値を検証したりサニタイズする必要があるかもしれません。
- SQL クエリー (SQL インジェクションにつながる可能性)
- ファイルオープン (パストラバーサルにつながる可能性)
- コマンド実行(潜在的なコマンドインジェクション)
- HTMLの組み立て(潜在的な XSS)
- など...
信頼できない Content-Type ヘッダー
HTTP ヘッダー Content-Type はクライアントによって操作が可能です。したがって、その値をセキュリティ上重要な決定では使用しないでください。
信頼できない Host ヘッダー
Host ヘッダーはクライアントによって操作が可能です。したがって、その値をセキュリティ上重要な決定では使用しないでください。
ServletRequest.getServerName()
と HttpServletRequest.getHeader("Host")
は、
どちらも Host
ヘッダーを抽出するという同じ動作をします。
GET /testpage HTTP/1.1
Host: www.example.com
[...]
アプリケーションにサービスを提供するウェブコンテナは、デフォルトでは、アプリケーションにリクエストをリダイレクトすることがあります。
これにより、悪意のあるユーザーがホストヘッダーで任意の値を配置できるようになります。
リクエストに関して行うセキュリティ上の決定において、この値を信頼しないことをお勧めします。
信頼できないセッションクッキーの値
メソッド HttpServletRequest.getRequestedSessionId()
は、クッキー JSESSIONID
の値を通常は返します。
この値は、セッション管理ロジックや平常でない開発者コードによって通常はアクセスされます。
クライアントに渡される値は一般的に英数字の値です (例えば JSESSIONID=jp6q31lq2myn
)。しかし、この値はクライアントによって改変することができます。
以下の HTTP リクエストは、その潜在的な変更の例を示しています。
GET /somePage HTTP/1.1
Host: yourwebsite.com
User-Agent: Mozilla/5.0
Cookie: JSESSIONID=Any value of the user's choice!!??'''">
そのため、JSESSIONID は、その値が既存のセッション ID と一致するかどうかを見るためだけに使用されるべきです。そうでない場合、そのユーザーは認証されていないユーザーであると考えるべきです。
加えて、セッション ID の値をログに記録してはいけません。その場合、ログファイルは有効でアクティブなセッション ID を含むことができ、ID が記録されかつアクティブなままであるすべてのセッションをハイジャックすることを内部者に許してしまいます。
参考文献
OWASP: Session Management Cheat Sheet
CWE-20: Improper Input Validation
信頼できないクエリー文字列
クエリー文字列は、GET パラメーターの名前と値を連結したものです。意図したパラメーター以外を渡すことができます。
URL リクエストが /app/servlet.htm?a=1&b=2
の場合は、クエリー文字列を抜き出すと a=1&b=2
になります。
HttpServletRequest.getParameter()
のようなメソッドを介して取得した個々のパラメーター値と同じように、
HttpServletRequest.getQueryString()
から得られた値は安全でないと考えるべきです。
センシティブな API に渡す前にクエリー文字列から取り出されたものを検証またはサニタイズする必要があるかもしれません。
信頼できない HTTP ヘッダー
リクエストヘッダーはリクエストしているユーザーによって容易に改ざんされることがあります。
一般的には、攻撃者によって変更なしに通常のブラウザーからリクエストが来ることを仮定するべきではありません。
そのため、リクエストに関して行うあらゆるセキュリティ上の決定において、その値を信頼しないことをお勧めします。
信頼できない Referer ヘッダー
動作:
- リクエストが悪意のあるユーザーからきている場合、任意の値をこのヘッダーに割り当てることができます。
- リクエストが安全 (https) である別のオリジンから開始された場合は、"Referer" は存在しません。
推奨事項:
- アクセス制御は、このヘッダーの値に基づいて行われるべきではありません。
- CSRF 保護は、この値のみに基いて行われるべきではありません(それはオプションであるため)
信頼できない User-Agent ヘッダー
ヘッダー "User-Agent" はクライアントによって容易になりすますことができます。ユーザーエージェントに基づいて (クローラー UA に対して) 異なった動作をすることはお勧めできません。
クッキー内に機密データの可能性
カスタムクッキーに格納する情報は、機密であったりセッションに関連したりするべきではありません。ほとんどの場合、機密データは、セッションのみに格納してユーザーのセッションクッキーによってのみ参照されるべきです。
HttpSession (HttpServletRequest.getSession()) を参照してください。
カスタムクッキーは、より長く保持する必要があって特定のセッションとは無関係な情報のために利用することができます。
参考文献
CWE-315: Cleartext Storage of Sensitive Information in a Cookie
潜在的なパストラバーサル (ファイル読み込み)
ファイルはその内容を読み込むために開かれていますが、ファイル名は入力パラメーターから生じています。
フィルターされていないパラメーターがこのファイル API に渡された場合、ファイルシステムの任意の場所からファイルを読み込めるかもしれません。
このルールは潜在的なパストラバーサルの脆弱性を特定します。多くの場合、組み立てられるファイルパスがユーザーによって操作されるとはありません。その場合、報告された事例は誤検知です。
参考文献
WASC: Path Traversal
OWASP: Path Traversal
CAPEC-126: Path Traversal
CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
潜在的なパストラバーサル (ファイル書き込み)
ファイルはその内容を書き込むために開かれていますが、ファイル名は入力パラメーターから生じています。
フィルターされていないパラメーターがこのファイル API に渡された場合、ファイルシステムの任意の場所からファイルを変更できるかもしれません。
このルールは潜在的なパストラバーサルの脆弱性を特定します。多くの場合、組み立てられるファイルパスがユーザーによって操作されるとはありません。その場合、報告された事例は誤検知です。
参考文献
WASC-33: Path Traversal
OWASP: Path Traversal
CAPEC-126: Path Traversal
CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
潜在的なコマンドインジェクション
強調表示された API は、システムコマンドを実行するために使用されています。フィルタリングされていない入力がこの API に渡された場合、任意のコマンド実行につながる可能性があります。
参考文献
OWASP: Command Injection
OWASP: Top 10 2013-A1-Injection
CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
FilenameUtils が Null バイトをフィルタリングしない
いくつかの FilenameUtils のメソッドは NULL バイト (0x00
) をフィルターしません。
Null バイトがファイル名に注入され、そのファイル名が OS に渡された場合、取得されるファイルは Null バイトの前で指定されたファイル名のものになります。
OS レベルであるので、たとえ Java 自体が Null バイトを気にしたり特別扱いしたりせずとも、すべての文字列は Null バイトが終端となります。
この OS の動作は、ファイル名の検証を「ファイル名の末尾 (例えば、末尾が ".log" であるか) を調べ、アクセスしても安全なファイルであるかを確認」といった具合にしていると回避されてしまうことがあります。
これを解決するには、2 つのことが推奨されています:
- Java 7 update 40 以降、または Java 8 以上へのアップグレード
ファイル名への NULL バイトインジェクションは、これらのバージョンで修正されています。
- 信頼できないユーザーによって与えられた任意のファイル名が有効であることを確認するため、入念に検証します (すなわち、null が含まれていないか、パス文字が加えられていないか、など)。
Null バイトインジェクションの影響を受けない最近のバージョンの Java を使っていることがわかっているなら、このルールを無効にしても構いません。
参考文献
WASC-28: Null Byte Injection
CWE-158: Improper Neutralization of Null Byte or NUL Character
TrustManager 実装が空
空の TrustManager 実装は、多くの場合、ルート認証局によって署名されていないホストに簡単に接続するために使用されます。
結果として、クライアントがどの証明書も信頼してしまうので、これは中間者攻撃に対して脆弱です。
(例えば、truststore に基づいて) 特定の証明書を許可する TrustManager を構築する必要があります。
適切な実装についての詳細は、こちらを:
[1]
[2]
参考文献
WASC-04: Insufficient Transport Layer Protection
CWE-295: Improper Certificate Validation
JAX-WS SOAP エンドポイントを発見
このメソッドは、SOAP Web サービス (JSR224) の一部です。
この Web サービスの安全性を分析する必要があります。例えば:
- 認証を強制した場合について、テストされるべきです。
- アクセス制御を強制した場合について、テストされるべきです。
- 入力は潜在的な脆弱性のために追跡されるべきです。
- 通信は理想的には SSL を介してでなければなりません。
参考文献
OWASP: Web Service Security Cheat Sheet
CWE-20: Improper Input Validation
JAX-RS REST エンドポイントを発見
このメソッドは REST Web サービス (JSR311) の一部です。
この Web サービスの安全性を分析する必要があります。例えば:
- 認証を強制した場合について、テストされるべきです。
- アクセス制御を強制した場合について、テストされるべきです。
- 入力は潜在的な脆弱性のために追跡されるべきです。
- 通信は理想的には SSL を介してでなければなりません。
- サービスが書き込みをサポートしている (例えば POST を用いて) 場合、CSRF に対する脆弱性を調査する必要があります。 [1]
参考文献
OWASP: REST Assessment Cheat Sheet
OWASP: REST Security Cheat Sheet
OWASP: Web Service Security Cheat Sheet
1. OWASP: Cross-Site Request Forgery
OWASP: CSRF Prevention Cheat Sheet
CWE-20: Improper Input Validation
Tapestry ページを発見
Tapestry エンドポイントがアプリケーションの起動時に発見されました。Tapestry アプリは、各ページのバッキング Java クラスと対応する Tapestry マークアップ言語ページ (.tml ファイル) で構成されています。
リクエストが受信されると、GET/POST パラメーターはバッキング Java クラス内の特定の入力にマッピングされます。
マッピングはいずれかで行われます。
フィールド名で:
[...]
protected String input;
[...]
または、明示的なアノテーションの定義で:
[...]
@org.apache.tapestry5.annotations.Parameter
protected String parameter1;
@org.apache.tapestry5.annotations.Component(id = "password")
private PasswordField passwordField;
[...]
ページは、ビュー [/resources/package/PageName].tml にマッピングされます。
このアプリケーションの各 Tapestry ページについて、このようにして自動的にマッピングされるすべての入力を使用される前に適切に検証されていることを確認するために調査するべきです。
参考文献
Apache Tapestry Home Page
CWE-20: Improper Input Validation
Wicket ページを発見
このクラスは、Wicket の WebPage を表します。 入力はコンストラクターに渡された PageParameters インスタンスから自動的に読み込まれます。
現在のページは、 ビュー [/package/WebPageName].html にマッピングされます。
このアプリケーションの各 Wicket ページについて、このようにして自動的にマッピングされるすべての入力を使用される前に適切に検証されていることを確認するために調査するべきです。
弱いメッセージダイジェスト
使用しているアルゴリズムは推奨されるメッセージダイジェストではありません。
NIST は、SHA-1、 SHA-224*、 SHA-256、 SHA-384、 SHA-512、 SHA-512/224、 または SHA-512/256 の使用を推奨しています。
* SHA-224 アルゴリズムは SUN プロバイダーでは提供していません。
承認されたアルゴリズムのいずれかを使用するように実装をアップグレードしてください。あなたのセキュリティ仕様要件に合った十分に強いアルゴリズムを使用してください。
参考文献
NIST Approved Hashing Algorithms
CWE-327: Use of a Broken or Risky Cryptographic Algorithm
メッセージダイジェストが独自
メッセージダイジェストを独自に実装すると、エラーを起こしやすくなります。
NIST は、SHA-1、 SHA-224*、 SHA-256、 SHA-384、 SHA-512、 SHA-512/224、 または SHA-512/256 の使用を推奨しています。
* SHA-224 アルゴリズムは SUN プロバイダーでは提供していません。
脆弱なコード:
MyProprietaryMessageDigest extends MessageDigest {
@Override
protected byte[] engineDigest() {
[...]
// 独創的なものは悪いアイデアです
return [...];
}
}
承認されたアルゴリズムのいずれかを使用するように実装をアップグレードしてください。あなたのセキュリティ仕様要件に合った十分に強いアルゴリズムを使用してください。
解決例:
MessageDigest sha256Digest = MessageDigest.getInstance("SHA256");
sha256Digest.update(password.getBytes());
参考文献
NIST Approved Hashing Algorithms
CWE-327: Use of a Broken or Risky Cryptographic Algorithm
汚染されたファイル名の読み取り
ファイルアップロード API によって与えられるファイル名は、権限のないファイルを参照するために、クライアントによって改ざんされていることがあります。
例えば:
"../../../config/overide_file"
"shell.jsp\u0000expected.gif"
したがって、そのような値はファイルシステム API に直接渡すべきではありません。
可能であれば、アプリケーションは独自のファイル名を生成して使用するべきです。
そうでなければ、その与えられたファイル名を、「許可されないパス文字 (例えば、/ \)が含まれていない」や「許可されたファイルを参照する」というように、正しい構成であるかを確認するために適切に検証するべきです。
参考文献
Securiteam: File upload security recommendations
CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
WASC-33: Path Traversal
OWASP: Path Traversal
CAPEC-126: Path Traversal
CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
正規表現による DoS (ReDoS)
正規表現 (regexs) は、しばしばサービス拒否 (DoS) 攻撃の対象となります (ReDoS と呼ばれます)。
これは、正規表現エンジンが、正規表現の定義によっては、特定の文字列を解析する際に時間がかかってしまうことに起因します。
例えば、 次の正規表現の場合: ^(a+)+$、 入力 "aaaaaaaaaaaaaaaaX
" を正規表現エンジンが 665535 の異なるパスを解析するようになります。
[1] OWASP リファレンスから抜粋した例
したがって、単一のリクエストがサーバー側で大量の計算を引き起こす可能性があります。
この正規表現(およびその他同様のもの)に関連する問題は、括弧の内側にある + (または *) と括弧の外側にある + (または *) のせいで、正規表現によって同じ入力文字を受け入れる異なる 2 つの方法があります。
この書き方は、どちらの + でも文字 'a' を消費できます。
これを修正するには、曖昧さを排除するために正規表現を書き換える必要があります。
例えば、^a+$ のようにたやすく書き換えることができます。それは、おそらく作者の意図していることです (a がいくつであっても) 。
元の正規表現の意図だとすれば、この新しい正規表現は、迅速に評価され、ReDoS の影響を受けません。
参考文献
Sebastian Kubeck's Weblog: Detecting and Preventing ReDoS Vulnerabilities
[1] OWASP: Regular expression Denial of Service
CWE-400: Uncontrolled Resource Consumption ('Resource Exhaustion')
XXE に脆弱な XML 解析 (SAXParser)
攻撃
信頼できないソースから受け取った XML の処理中に、XML パーサーが XML エンティティをサポートしていると、XML 外部エンティティ (XXE) 攻撃が発生する可能性があります。
リスク 1: ローカルファイルの内容が暴露 (XXE: XML eXternal Entity)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd" > ]>
<foo>&xxe;</foo>
リスク 2: サービス拒否 (XEE: Xml Entity Expansion)
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ELEMENT lolz (#PCDATA)>
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
[...]
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
解決策
XMLパーサーの危険な機能を露呈しないようにするには、コードに以下の変更を行ってください。
脆弱なコード:
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse(inputStream, customHandler);
"Secure processing" モードを使用した解決策:
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
SAXParser parser = spf.newSAXParser();
parser.parse(inputStream, customHandler);
DTD を無効にする解決策:
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
SAXParser parser = spf.newSAXParser();
parser.parse(inputStream, customHandler);
参考文献
CWE-611: Improper Restriction of XML External Entity Reference ('XXE')
CERT: IDS10-J. Prevent XML external entity attacks
OWASP.org: XML External Entity (XXE) Processing
WS-Attacks.org: XML Entity Expansion
WS-Attacks.org: XML External Entity DOS
WS-Attacks.org: XML Entity Reference Attack
Xerces complete features list
XXE に脆弱な XML 解析 (XMLReader)
攻撃
信頼できないソースから受け取った XML の処理中に、XML パーサーが XML エンティティをサポートしていると、XML 外部エンティティ (XXE) 攻撃が発生する可能性があります。
リスク 1: ローカルファイルの内容が暴露 (XXE: XML eXternal Entity)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd" > ]>
<foo>&xxe;</foo>
リスク 2: サービス拒否 (XEE: Xml Entity Expansion)
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ELEMENT lolz (#PCDATA)>
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
[...]
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
解決策
XMLパーサーの危険な機能を露呈しないようにするには、コードに以下の変更を行ってください。
脆弱なコード:
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setContentHandler(customHandler);
reader.parse(new InputSource(inputStream));
"Secure processing" モードを使用した解決策:
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
reader.setContentHandler(customHandler);
reader.parse(new InputSource(inputStream));
DTD を無効にする解決策:
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
reader.setContentHandler(customHandler);
reader.parse(new InputSource(inputStream));
参考文献
CWE-611: Improper Restriction of XML External Entity Reference ('XXE')
CERT: IDS10-J. Prevent XML external entity attacks
OWASP.org: XML External Entity (XXE) Processing
WS-Attacks.org: XML Entity Expansion
WS-Attacks.org: XML External Entity DOS
WS-Attacks.org: XML Entity Reference Attack
Xerces complete features list
XXE に脆弱な XML 解析 (DocumentBuilder)
攻撃
信頼できないソースから受け取った XML の処理中に、XML パーサーが XML エンティティをサポートしていると、XML 外部エンティティ (XXE) 攻撃が発生する可能性があります。
リスク 1: ローカルファイルの内容が暴露 (XXE: XML eXternal Entity)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd" > ]>
<foo>&xxe;</foo>
リスク 2: サービス拒否 (XEE: Xml Entity Expansion)
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ELEMENT lolz (#PCDATA)>
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
[...]
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
解決策
XMLパーサーの危険な機能を露呈しないようにするには、コードに以下の変更を行ってください。
脆弱なコード:
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = db.parse(input);
"Secure processing" モードを使用した解決策:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(input);
DTD を無効にする解決策:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(input);
参考文献
CWE-611: Improper Restriction of XML External Entity Reference ('XXE')
CERT: IDS10-J. Prevent XML external entity attacks
OWASP.org: XML External Entity (XXE) Processing
WS-Attacks.org: XML Entity Expansion
WS-Attacks.org: XML External Entity DOS
WS-Attacks.org: XML Entity Reference Attack
Xerces2 complete features list
潜在的な XPath インジェクション
XPath インジェクションのリスクは、SQL インジェクションに似ています。XPath クエリーに信頼できないユーザー入力が含まれている場合は、全データソースを暴露されるかもしれません。
これにより、攻撃者に権限のないデータにアクセスされたり、対象のXMLを不当に変更されたりする可能性があります。
参考文献
WASC-39: XPath Injection
OWASP: Top 10 2013-A1-Injection
CWE-643: Improper Neutralization of Data within XPath Expressions ('XPath Injection')
CERT: IDS09-J. Prevent XPath Injection (archive)
Black Hat Europe 2012: Hacking XPath 2.0
Balisage: XQuery Injection
Struts 1 アクション を発見
このクラスは Struts 1 アクションです。
リクエストがこのコントローラーにルーティングされると、Form オブジェクトは HTTP パラメーターを含んで自動的にインスタンス化されます。
これらのパラメーターの使用について、それらが安全に使用されているかを確認するためにレビューすべきです。
Struts 2 のエンドポイントを発見
Struts 2 では、エンドポイントはプレーンオールド Java オブジェクト (POJO) です。すなわち、インタフェース/クラスを実装/継承する必要がないということです。
リクエストがそのコントローラー (選択されたクラス) にルーティングされると、与えられた HTTP パラメーターが自動的にクラスのセッターにマッピングされます。
そのため、フォームにそれらの値が含まれていない場合でも、このクラスのすべてのセッターは信頼できない入力として考慮されるべきです。
そのオブジェクトにそのようなセッターがある限り、攻撃者はリクエストに追加の値を容易に与えることができ、オブジェクトに設定されます。
これらのパラメーターの使用について、それらが安全に使用されているかを確認するためにレビューすべきです。
Spring のエンドポイントを発見
このクラスは、Spring コントローラーです。RequestMapping
で注釈付けしたすべてのメソッドは、リモートから到達可能です。
リモートに公開したメソッドが潜在的な攻撃者に公開しても安全であるかを確認するために、このクラスを分析する必要があります。
インジェクションの可能性
特定されたメソッドはインジェクションの影響を受けやすいです。入力は、検証して適切にエスケープする必要があります。
脆弱なコードのサンプル:
SqlUtil.execQuery("select * from UserEntity t where id = " + parameterInput);
追加のインジェクションソースの構成:
この検出器を使用するには手動での設定が必要です。
形式に従って設定ファイルを作成します:
<<呼び出し命令>>|<<クラス名>>|<<メソッド>>|<<パラメーターシグネチャー>>=<<インジェクション可能なパラメーターのインデックス>>|<<検出器の説明の表示>>
例えば:
INVOKEVIRTUAL|testcode/sqli/MySqlWrapper|executeQuery|(Ljava/lang/String;)Ljava/sql/ResultSet;=0|CUSTOM_INJECTION
[...]
この問題はシステムプロパティが設定されてはじめて動作します。
-Dfindsecbugs.injection.sources=${basedir}/rules/InjectionSources.properties
参考文献
WASC-19: SQL Injection
OWASP: Top 10 2013-A1-Injection
OWASP: SQL Injection Prevention Cheat Sheet
OWASP: Query Parameterization Cheat Sheet
CAPEC-66: SQL Injection
CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
潜在的な SQL/HQL インジェクション (Hibernate)
SQL クエリーに含まれる入力値は安全に渡される必要があります。
プリペアードステートメントのバインド変数は、SQL インジェクションのリスクを容易に軽減するために使用することができます。
プリペアードステートメントの代わりに、 Hibernate Criteria を使用できます。
脆弱なコード:
Session session = sessionFactory.openSession();
Query q = session.createQuery("select t from UserEntity t where id = " + input);
q.execute();
解決策:
Session session = sessionFactory.openSession();
Query q = session.createQuery("select t from UserEntity t where id = :userId");
q.setString("userId",input);
q.execute();
動的クエリーの解決策 (Hibernate Criteria を使った):
Session session = sessionFactory.openSession();
Query q = session.createCriteria(UserEntity.class)
.add( Restrictions.like("id", input) )
.list();
q.execute();
参考文献 (Hibernate)
Hibernate Documentation: Query Criteria
Hibernate Javadoc: Query Object
HQL for pentesters: 疑わしいコードが悪用可能かをテストするためのガイドライン
参考文献 (SQL インジェクション)
WASC-19: SQL Injection
CAPEC-66: SQL Injection
CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
OWASP: Top 10 2013-A1-Injection
OWASP: SQL Injection Prevention Cheat Sheet
OWASP: Query Parameterization Cheat Sheet
潜在的な SQL/JDOQL インジェクション (JDO)
SQL クエリーに含まれる入力値は安全に渡される必要があります。
プリペアードステートメントのバインド変数は、SQL インジェクションのリスクを容易に軽減するために使用することができます。
脆弱なコード:
PersistenceManager pm = getPM();
Query q = pm.newQuery("select * from Users where name = " + input);
q.execute();
解決策:
PersistenceManager pm = getPM();
Query q = pm.newQuery("select * from Users where name = nameParam");
q.declareParameters("String nameParam");
q.execute(input);
参考文献 (JDO)
JDO: Object Retrieval
参考文献 (SQL インジェクション)
WASC-19: SQL Injection
CAPEC-66: SQL Injection
CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
OWASP: Top 10 2013-A1-Injection
OWASP: SQL Injection Prevention Cheat Sheet
OWASP: Query Parameterization Cheat Sheet
潜在的な SQL/JPQL インジェクション (JPA)
SQL クエリーに含まれる入力値は安全に渡される必要があります。
プリペアードステートメントのバインド変数は、SQL インジェクションのリスクを容易に軽減するために使用することができます。
脆弱なコード:
EntityManager pm = getEM();
TypedQuery q = em.createQuery(
String.format("select * from Users where name = %s", username),
UserEntity.class);
UserEntity res = q.getSingleResult();
解決策:
TypedQuery q = em.createQuery(
"select * from Users where name = usernameParam",UserEntity.class)
.setParameter("usernameParam", username);
UserEntity res = q.getSingleResult();
参考文献 (JPA)
The Java EE 6 Tutorial: Creating Queries Using the Java Persistence Query Language
参考文献 (SQL インジェクション)
WASC-19: SQL Injection
CAPEC-66: SQL Injection
CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
OWASP: Top 10 2013-A1-Injection
OWASP: SQL Injection Prevention Cheat Sheet
OWASP: Query Parameterization Cheat Sheet
潜在的な JDBC インジェクション (Spring JDBC)
SQL クエリーに含まれる入力値は安全に渡される必要があります。
プリペアードステートメントのバインド変数は、SQL インジェクションのリスクを容易に軽減するために使用することができます。
脆弱なコード:
JdbcTemplate jdbc = new JdbcTemplate();
int count = jdbc.queryForObject("select count(*) from Users where name = '"+paramName+"'", Integer.class);
解決策:
JdbcTemplate jdbc = new JdbcTemplate();
int count = jdbc.queryForObject("select count(*) from Users where name = ?", Integer.class, paramName);
参考文献 (Spring JDBC)
Spring Official Documentation: Data access with JDBC
参考文献 (SQL インジェクション)
WASC-19: SQL Injection
CAPEC-66: SQL Injection
CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
OWASP: Top 10 2013-A1-Injection
OWASP: SQL Injection Prevention Cheat Sheet
OWASP: Query Parameterization Cheat Sheet
潜在的な JDBC インジェクション
SQL クエリーに含まれる入力値は安全に渡される必要があります。
プリペアードステートメントのバインド変数は、SQL インジェクションのリスクを容易に軽減するために使用することができます。
脆弱なコード:
Connection conn = [...];
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("update COFFEES set SALES = "+nbSales+" where COF_NAME = '"+coffeeName+"'");
解決策:
Connection conn = [...];
conn.prepareStatement("update COFFEES set SALES = ? where COF_NAME = ?");
updateSales.setInt(1, nbSales);
updateSales.setString(2, coffeeName);
参考文献 (JDBC)
Oracle Documentation: The Java Tutorials > Prepared Statements
参考文献 (SQL インジェクション)
WASC-19: SQL Injection
CAPEC-66: SQL Injection
CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
OWASP: Top 10 2013-A1-Injection
OWASP: SQL Injection Prevention Cheat Sheet
OWASP: Query Parameterization Cheat Sheet
潜在的な LDAP インジェクション
SQL と同様に、LDAP クエリーに渡したすべての入力は安全に渡される必要があります。 残念ながら、LDAP には、SQL のようなプリペアードステートメントインタフェースがありません。
そのため、LDAP インジェクションに対する一番の防御は、LDAP クエリーに含める前にあらゆる信頼できないデータを十分に検証することです。
リスクのあるコード:
NamingEnumeration answers = context.search("dc=People,dc=example,dc=com",
"(uid=" + username + ")", ctrls);
参考文献
WASC-29: LDAP Injection
OWASP: Top 10 2013-A1-Injection
CWE-90: Improper Neutralization of Special Elements used in an LDAP Query ('LDAP Injection')
LDAP Injection Guide: Learn How to Detect LDAP Injections and Improve LDAP Security
スクリプトエンジン使用時の潜在的なコードインジェクション
動的なコードが評価されています。コードの構成を慎重に分析してください。
悪意のあるコードの実行は、データ漏洩やオペレーティングシステムへの不正侵入につながる可能性があります。
ユーザーコードの評価が意図される場合、適切なサンドボックスが適用されるべきです (参考文献を参照)。
リスクのあるコード:
public void runCustomTrigger(String script) {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
engine.eval(script); //ここで悪いことが起こりうる。
}
解決策:
"Cloudbees Rhino Sandbox" ライブラリーを使うことで、JavaScript コードの安全な評価を行います。
public void runCustomTrigger(String script) {
SandboxContextFactory contextFactory = new SandboxContextFactory();
Context context = contextFactory.makeContext();
contextFactory.enterContext(context);
try {
ScriptableObject prototype = context.initStandardObjects();
prototype.setParentScope(null);
Scriptable scope = context.newObject(prototype);
scope.setPrototype(prototype);
context.evaluateString(scope,script, null, -1, null);
} finally {
context.exit();
}
}
参考文献
Cloudbees Rhino Sandbox: Rhino のサンドボックスを作成するためのユーティリティ (すべてのクラスへのアクセスをブロック)
CodeUtopia.net: Sandboxing Rhino in Java
Remote Code Execution .. by design: 悪意のあるペイロードの例。示したサンプルは、サンドボックスのルールをテストするために使用することができます。
CWE-94: Improper Control of Generation of Code ('Code Injection')
CWE-95: Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection')
Spring 式使用時の潜在的なコードインジェクション
Spring 式は、動的な値で構築されています。
値のソースを、フィルタリングされていない値がこの危険なコード評価に陥ることを避けるために確認する必要があります。
リスクのあるコード:
public void parseExpressionInterface(Person personObj,String property) {
ExpressionParser parser = new SpelExpressionParser();
//入力がユーザーの制御にある場合は、危険..
Expression exp = parser.parseExpression(property+" == 'Albert'");
StandardEvaluationContext testContext = new StandardEvaluationContext(personObj);
boolean result = exp.getValue(testContext, Boolean.class);
[...]
参考文献
CWE-95: Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection')
CWE-94: Improper Control of Generation of Code ('Code Injection')
Spring Expression Language (SpEL) - Official Documentation
Minded Security: Expression Language Injection
Remote Code Execution .. by design: 悪意のあるペイロードの例。示したサンプルは、サンドボックスのルールをテストするために使用することができます。
不適切な16進数の連結
ハッシュシグネチャーを含むバイト列を人間が読める文字列に変換するとき、配列をバイト単位に読み取っていると変換ミスを起こすことがあります。
次のサンプルでは、計算されたハッシュ値の各バイトから先行ゼロをトリミングする Integer.toHexString() を例示しています。
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] resultBytes = md.digest(password.getBytes("UTF-8"));
StringBuilder stringBuilder = new StringBuilder();
for(byte b :resultBytes) {
stringBuilder.append( Integer.toHexString( b & 0xFF ) );
}
return stringBuilder.toString();
この間違いによって、多くの衝突を招き、計算されたハッシュ値を弱めます。
例えば、上記の機能によって、ハッシュ値 "0x0679" と "0x6709" はいずれも "679" のように出力されます。
このような状況では、次のように toHexString() の使用を String.format() に置き換えるべきです:
stringBuilder.append( String.format( "%02X", b ) );
Hazelcast の対称暗号化
Hazelcast のネットワーク通信は、対称暗号 (おそらく DES または blowfish) を使用するように構成されています。
これらの暗号だけでは、完全性や安全な認証を提供しません。非対称暗号化を使用することが好ましいです。
参考文献
WASC-04: Insufficient Transport Layer Protection
Hazelcast Documentation: Encryption (see second part)
CWE-326: Inadequate Encryption Strength
NullCipher は危険
NullCipher は、本番アプリケーションで意図して使われることはめったにありません。これは、与えられた平文と同じ暗号文を返すように Cipher インタフェースを実装しています。
テストなど、幾ばくかのコンテキストでは NullCipher が適切な場合があります。
脆弱なコード:
Cipher doNothingCihper = new NullCipher();
[...]
//生成される暗号文は平文と同じになります。
byte[] cipherText = c.doFinal(plainText);
解決策:
NullCipher の使用を避けます。その不慮の使用が重大な機密性リスクを招く可能性があります。
参考文献
CWE-327: Use of a Broken or Risky Cryptographic Algorithm
暗号化されていないソケット
使用する通信チャネルは暗号化されていません。そのトラフィックは、ネットワークトラフィックを傍受している攻撃者によって読み取られるかもしれません。
脆弱なコード:
プレーンソケット (平文通信):
Socket soc = new Socket("www.google.com",80);
解決策:
SSL ソケット (安全な通信):
Socket soc = SSLSocketFactory.getDefault().createSocket("www.google.com", 443);
SSL ソケットを使用する以外にも、使っている SSLSocketFactory が中間者攻撃を受けていないことを確認するためにすべて妥当な証明書であるかの検証を行っていることをを確認する必要があります。
その正しい方法の詳細については、OWASP Transport Layer Protection Cheat Sheet をお読みください。
参考文献
OWASP: Top 10 2010-A9-Insufficient Transport Layer Protection
OWASP: Top 10 2013-A6-Sensitive Data Exposure
OWASP: Transport Layer Protection Cheat Sheet
WASC-04: Insufficient Transport Layer Protection
CWE-319: Cleartext Transmission of Sensitive Information
DES / DESede は危険
DES および DESede (3DES) は、最新のアプリケーションのための強固な暗号とは見なされていません。
現在、NIST は DES/3DES の代わりに AES ブロック暗号の使用を推奨しています。
脆弱なコードの例:
Cipher c = Cipher.getInstance("DESede/ECB/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, k, iv);
byte[] cipherText = c.doFinal(plainText);
解決策の例:
Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
c.init(Cipher.ENCRYPT_MODE, k, iv);
byte[] cipherText = c.doFinal(plainText);
参考文献
NIST Withdraws Outdated Data Encryption Standard
CWE-326: Inadequate Encryption Strength
RSA NoPadding は危険
このソフトウェアは、RSA アルゴリズムを使用していますが、最適非対称暗号化パディング (OAEP) を取り入れていないので、暗号化を弱める可能性があります。
脆弱なコード:
Cipher.getInstance("RSA/NONE/NoPadding")
解決策:
コードを以下と置き換えるべきです:
Cipher.getInstance("RSA/ECB/OAEPWithMD5AndMGF1Padding")
参考文献
CWE-780: Use of RSA Algorithm without OAEP
Root Labs: Why RSA encryption padding is critical
ハードコードされたパスワード
パスワードは、ソースコード内に保持すべきではありません。ソースコードは、企業環境では広く共有されることがあり、オープンソースでは確実に共有されています。
安全に管理されるようにするには、パスワードや秘密鍵は別個の設定ファイルやキーストアに保存するべきです。
(ハードコードされた鍵は別途ハードコードされた鍵パターンで報告されます)
脆弱なコード:
private String SECRET_PASSWORD = "letMeIn!";
Properties props = new Properties();
props.put(Context.SECURITY_CREDENTIALS, "p@ssw0rd");
ハードコードされた鍵
暗号化鍵は、ソースコード内に保持すべきではありません。ソースコードは、企業環境では広く共有されることがあり、オープンソースでは確実に共有されています。
安全に管理されるようにするには、パスワードや秘密鍵は別個の設定ファイルやキーストアに保存するべきです。
(ハードコードされたパスワードは別途ハードコードされたパスワードパターンで報告されます)
脆弱なコード:
byte[] key = {1, 2, 3, 4, 5, 6, 7, 8};
SecretKeySpec spec = new SecretKeySpec(key, "AES");
Cipher aes = Cipher.getInstance("AES");
aes.init(Cipher.ENCRYPT_MODE, spec);
return aesCipher.doFinal(secretData);
入力検証のない Struts フォーム
フォーム入力には、最低限の入力検証が必要です。予防検証は様々なリスクに対する多層防御の提供に役立ちます。
検証は、 validate
メソッドを実装することで導入されます。
public class RegistrationForm extends ValidatorForm {
private String name;
private String email;
[...]
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
//HttpRequest を経由して渡された名前と電子メールのパラメーターの検証コードをここに
}
}
参考文献
CWE-20: Improper Input Validation
CWE-106: Struts: Plug-in Framework not in Use
XSSRequestWrapper は脆弱な XSS 保護
XSSRequestWrapper
と呼ばれる HttpServletRequestWrapper
の実装は、様々なブログサイトで公開されていました。
[1]
[2]
いくつかの理由があるため、このフィルターは脆弱です。:
- カバーしているのはパラメーターのみで、ヘッダーやサイドチャネルの入力はカバーしていない
- 置換の連鎖を容易に迂回できる (以下の例を参照)
- 特異な悪いパターンから成るブラックリスト (それよりも、正常/有効な入力から成るホワイトリスト)
迂回の例:
<scrivbscript:pt>alert(1)</scrivbscript:pt>
前述の入力は "<script>alert(1)</script>"
に変換されます。
"vbscript:"
の除去は、"<script>.*</script>"
の置換が行われた後です。
強力な保護のためには、OWASP XSS Prevention Cheat Sheet に定義された XSS 保護ルールに従っている、ビュー (テンプレート、jsp、...) で自動的に文字をエンコードするソリューションを採用します。
参考文献
WASC-8: Cross Site Scripting
OWASP: XSS Prevention Cheat Sheet
OWASP: Top 10 2013-A3: Cross-Site Scripting (XSS)
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
弱い鍵長での Blowfish の使用
Blowfish 暗号は、32 ビットから 448 ビットまでの鍵長をサポートしています。短い鍵長は、ブルートフォース攻撃に対して脆弱な暗号文を作ります。
Blowfish を使い続ける場合は、キーを生成するときは少なくとも 128 ビットのエントロピーを使用する必要があります。
アルゴリズムを変更できるのなら、AES ブロック暗号を代わりとして使用するべきです。
脆弱なコード:
KeyGenerator keyGen = KeyGenerator.getInstance("Blowfish");
keyGen.init(64);
解決策:
KeyGenerator keyGen = KeyGenerator.getInstance("Blowfish");
keyGen.init(128);
参考文献
Blowfish (cipher)
CWE-326: Inadequate Encryption Strength
弱い鍵長での RSA の使用
RSA 研究所は、現在、企業利用向けには 1024 ビット、認証局によって使用されるルート鍵ペアのような重要な鍵向けには 2048 ビットの鍵長を推奨しています。
[1]
脆弱なコード:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(512);
解決策:
KeyPairGenerator の作成は、次のように少なくとも 2048 ビットの鍵長にするべきです。
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
参考文献
[1] RSA Laboratories: 3.1.5 How large a key should be used in the RSA cryptosystem?
Wikipedia: Asymmetric algorithm key lengths
CWE-326: Inadequate Encryption Strength
Keylength.com (BlueKrypt): Aggregate key length recommendations.
未検証のリダイレクト
アプリケーションが検証されていないユーザー指定のパラメーターで指定された宛先 URL にユーザーをリダイレクトするとき、未検証のリダイレクトが発生します。
このような脆弱性は、フィッシング攻撃を容易にするために使用することができます。
シナリオ
1. ユーザーが騙されて悪意のある URL を訪れる: http://website.com/login?redirect=http://evil.vvebsite.com/fake/login
2. ユーザーは信頼する Web サイトのように見える偽のログインページにリダイレクトされる。 (http://evil.vvebsite.com/fake/login)
3. ユーザーが資格情報を入力する。
4. 悪意のあるサイトは、ユーザーの資格情報を盗み、そして元の Web サイトにリダイレクトする。
この攻撃は、ほとんどのユーザーがリダイレクト後に URL を再確認しないので、もっともらしいです。
また、認証ページヘのリダイレクトは非常に一般的です。
脆弱なコード:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
[...]
resp.sendRedirect(req.getParameter("redirectUrl"));
[...]
}
解決策/対策:
- ユーザーからリダイレクト先を受け入れない
- 宛先のキーを受け入れ、それを使って目的の (正当な) 行き先をルックアップする
- 相対パスのみを受け入れる
- URL のホワイトリスト (可能であれば)
- URL の先頭がホワイトリストの一部であるかを検証する
参考文献
WASC-38: URL Redirector Abuse
OWASP: Top 10 2013-A10: Unvalidated Redirects and Forwards
OWASP: Unvalidated Redirects and Forwards Cheat Sheet
CWE-601: URL Redirection to Untrusted Site ('Open Redirect')
JSP 内の潜在的な XSS
潜在的な XSS が見つかりました。これは、クライアントのブラウザーで不要な JavaScript を実行するために使用される可能性があります。 (参考文献を参照してください)
脆弱なコード:
<%
String taintedInput = (String) request.getAttribute("input");
%>
[...]
<%= taintedInput %>
解決策:
<%
String taintedInput = (String) request.getAttribute("input");
%>
[...]
<%= Encode.forHtml(taintedInput) %>
XSS に対する最善の防御策は、上記の例のような状況に応じた出力のエンコーディングです。
考慮すべき 4 つの状況が一般的にはあります: HTML、JavaScript、CSS (スタイル)、および URL。
これらの防御策の重要な詳細を説明する OWASP XSS Prevention Cheat Sheet に定義された XSS 保護ルールに従ってください。
参考文献
WASC-8: Cross Site Scripting
OWASP: XSS Prevention Cheat Sheet
OWASP: Top 10 2013-A3: Cross-Site Scripting (XSS)
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
OWASP Java Encoder
サーブレット内の 潜在的な XSS
潜在的な XSS が見つかりました。これは、クライアントのブラウザーで不要な JavaScript を実行するために使用される可能性があります。 (参考文献を参照してください)
脆弱なコード:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String input1 = req.getParameter("input1");
[...]
resp.getWriter().write(input1);
}
解決策:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String input1 = req.getParameter("input1");
[...]
resp.getWriter().write(Encode.forHtml(input1));
}
XSS に対する最善の防御策は、上記の例のような状況に応じた出力のエンコーディングです。
考慮すべき 4 つの状況が一般的にはあります: HTML、JavaScript、CSS (スタイル)、および URL。
これらの防御策の重要な詳細を説明する OWASP XSS Prevention Cheat Sheet に定義された XSS 保護ルールに従ってください。
このサーブレット内の XSS ルールは同様の問題を探しますが、FindBugs の既存ルール「XSS: 反射型クロスサイトスクリプティング脆弱性があるサーブレット」と「XSS: 反射型クロスサイトスクリプティング脆弱性がエラーページにあるサーブレット」とは異なる方法でそれらを探すことに注意してください。
参考文献
WASC-8: Cross Site Scripting
OWASP: XSS Prevention Cheat Sheet
OWASP: Top 10 2013-A3: Cross-Site Scripting (XSS)
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
OWASP Java Encoder
XMLDecoder の使用
XMLDecoder は、信頼できないデータを解析するために使用すべきではありません。
ユーザー入力をデシリアライズすると、任意のコードが実行される可能性があります。
XMLDecoder は任意のメソッド呼び出しをサポートしているので、これは可能です。
この機能はセッターメソッドの呼び出しを意図しているが、実際には任意のメソッドを呼び出すことができます。
悪意のある XML の例:
<?xml version="1.0" encoding="UTF-8" ?>
<java version="1.4.0" class="java.beans.XMLDecoder">
<object class="java.io.PrintWriter">
<string>/tmp/Hacked.txt</string>
<void method="println">
<string>Hello World!</string>
</void>
<void method="close"/>
</object>
</java>
前述の XML コードによって、"Hello World!" という内容のファイルの作成を引き起こします。
脆弱なコード:
XMLDecoder d = new XMLDecoder(in);
try {
Object result = d.readObject();
}
[...]
解決策:
解決策は、信頼できないソースからのコンテンツの解析に XMLDecoder を使用しないようにすることです。
参考文献
Dinis Cruz Blog: Using XMLDecoder to execute server-side Java Code on an Restlet application
RedHat blog : Java deserialization flaws: Part 2, XML deserialization
CWE-20: Improper Input Validation
静的な IV
メッセージを暗号化するごとに初期化ベクトルは再生成する必要があります。
脆弱なコード:
private static byte[] IV = new byte[16] {(byte)0,(byte)1,(byte)2,[...]};
public void encrypt(String message) throws Exception {
IvParameterSpec ivSpec = new IvParameterSpec(IV);
[...]
解決策:
public void encrypt(String message) throws Exception {
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
[...]
参考文献
Wikipedia: Initialization vector
CWE-329: Not Using a Random IV with CBC Mode
Encryption - CBC Mode IV: Secret or Not?
ECB モードは危険
暗号化データにより良い機密性をもたらす認証付き暗号モードを、機密性が低い Electronic Codebook (ECB) モードの代わりに使用するべきです。
具体的は、ECB モードは同じ入力のたびに同じ出力を生成します。
したがって、例えば、ユーザーがパスワードを送信している場合には、暗号された値は毎回同じになります。
これは、反射攻撃を許してしまいます。
これを修正するには、Galois/Counter Mode (GCM) のようなものを代わりに使用するべきです。
リスクのあるコード:
Cipher c = Cipher.getInstance("AES/ECB/NoPadding");
c.init(Cipher.ENCRYPT_MODE, k, iv);
byte[] cipherText = c.doFinal(plainText);
解決策:
Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
c.init(Cipher.ENCRYPT_MODE, k, iv);
byte[] cipherText = c.doFinal(plainText);
参考文献
Wikipedia: Authenticated encryption
NIST: Authenticated Encryption Modes
Wikipedia: Block cipher modes of operation
NIST: Recommendation for Block Cipher Modes of Operation
パディングオラクルの影響を受けやすい暗号
この特定のモード (PKCS5Padding を使った CBC) は、パディングオラクル攻撃を受けやすいです。
システムが有効なパディングもしくは無効なパディングを持つ平文との違いをさらした場合、敵がメッセージを解読できるようになるかもしれません。
有効および無効なパッディングとの区別は、条件ごとに返される独特なエラーメッセージを通じて通常は明らかにされます。
リスクのあるコード:
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, k, iv);
byte[] cipherText = c.doFinal(plainText);
解決策:
Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
c.init(Cipher.ENCRYPT_MODE, k, iv);
byte[] cipherText = c.doFinal(plainText);
参考文献
Padding Oracles for the masses (by Matias Soler)
Wikipedia: Authenticated encryption
NIST: Authenticated Encryption Modes
CAPEC: Padding Oracle Crypto Attack
CWE-696: Incorrect Behavior Order
完全性に欠ける暗号
この生成された暗号文は、敵による変更の影響を受けやすいです。これは、データが改ざんされてしまったことを検出する方法を暗号が提供しないことを意味します。
暗号文が攻撃者によって操作できる場合、検出されずに変更されるかもしれません。
解決策は、データに署名するためのハッシュベースのメッセージ認証符号 (HMAC) を含む暗号を使用することです。
既存の暗号に HMAC 関数を組み合わせると、エラーを起こしやすいです [1]。
厳密に言えば、まず HMAC を検証すべきであり、データが修正されていない場合に限り、そのデータに使われた暗号関数を実行することが常に推奨されています。
リスクのあるコード:
CBC モードで AES
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, k, iv);
byte[] cipherText = c.doFinal(plainText);
ECB モードとトリプル DES
Cipher c = Cipher.getInstance("DESede/ECB/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, k, iv);
byte[] cipherText = c.doFinal(plainText);
解決策:
Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
c.init(Cipher.ENCRYPT_MODE, k, iv);
byte[] cipherText = c.doFinal(plainText);
上記の解決策の例では、GCM モードは、結果に完全性があれば、その結果生じる暗号化データに HMAC を挿入します。
参考文献
Wikipedia: Authenticated encryption
NIST: Authenticated Encryption Modes
Moxie Marlinspike's blog: The Cryptographic Doom Principle
CWE-353: Missing Support for Integrity Check
ESAPI Encryptor の使用
ESAPI には、暗号化コンポーネント内にちょっとした脆弱性の前歴があります。
期待通りに認証付き暗号が機能していることを確認する手っ取り早い検証リストを以下に示します。
1. ライブラリーのバージョン
この問題は、ESAPI のバージョン 2.1.0 で修正されています。バージョン 2.0.1 以前は、MAC バイパスに対して脆弱です (CVE-2013-5679)。
Maven ユーザーの場合、プラグイン versions を、次のコマンドを使って呼び出すことができます。
ESAPI の実際のバージョンは、その出力で入手できます。
$ mvn versions:display-dependency-updates
出力:
[...]
[INFO] The following dependencies in Dependencies have newer versions:
[INFO] org.slf4j:slf4j-api ................................... 1.6.4 -> 1.7.7
[INFO] org.owasp.esapi:esapi ................................. 2.0.1 -> 2.1.0
[...]
または、直接設定を見ることによって
<dependency>
<groupId>org.owasp.esapi</groupId>
<artifactId>esapi</artifactId>
<version>2.1.0</version>
</dependency>
Ant ユーザーの場合、使用される jar は esapi-2.1.0.jar でなければなりません。
2. 設定:
このライブラリーのバージョン 2.1.0 は、暗号文の定義で変更される鍵長に対して未だに脆弱です (CVE-2013-5960)。いくつかの予防措置をとる必要があります。
これらの要素のいずれかが存在する場合、ESAPI の暗号化の設定も脆弱になることがあります:
安全でない設定:
Encryptor.CipherText.useMAC=false
Encryptor.EncryptionAlgorithm=AES
Encryptor.CipherTransformation=AES/CBC/PKCS5Padding
Encryptor.cipher_modes.additional_allowed=CBC
安全な設定:
#設定する必要があります
Encryptor.CipherText.useMAC=true
#信頼できる認証付き暗号を設定する必要があります
Encryptor.EncryptionAlgorithm=AES
Encryptor.CipherTransformation=AES/GCM/NoPadding
#パディングオラクルを避けるために CBC モードを削除する必要があります
Encryptor.cipher_modes.additional_allowed=
参考文献
ESAPI Security bulletin 1 (CVE-2013-5679)
Vulnerability Summary for CVE-2013-5679
Synactiv: Bypassing HMAC validation in OWASP ESAPI symmetric encryption
CWE-310: Cryptographic Issues
ESAPI-dev mailing list: Status of CVE-2013-5960
外部ファイルアクセス (Android)
このアプリケーションは外部ストレージ (SD カードである可能性があります) にデータを書き込みます。このアクションには複数のセキュリティへの影響があります。
まず、 SD カード上のファイルストアは READ_EXTERNAL_STORAGE
権限を持つアプリケーションにアクセスできるようになります。
また、永続化したデータにユーザーに関する機密情報が含まれている場合は、暗号化が必要でしょう。
リスクのあるコード:
file file = new File(getExternalFilesDir(TARGET_TYPE), filename);
fos = new FileOutputStream(file);
fos.write(confidentialData.getBytes());
fos.flush();
より良い代替手段:
fos = openFileOutput(filename, Context.MODE_PRIVATE);
fos.write(string.getBytes());
参考文献
Android Official Doc: Security Tips
CERT: DRD00-J: Do not store sensitive information on external storage [...]
Android Official Doc: Using the External Storage
OWASP Mobile Top 10 2014-M2: Insecure Data Storage
CWE-312: Cleartext Storage of Sensitive Information
ブロードキャスト (Android)
ブロードキャストインテントは、適切な権限を持つ任意のアプリケーションで受け取ることができます。
できる限り機密情報の送信を避けることをお勧めします。
リスクのあるコード:
Intent i = new Intent();
i.setAction("com.insecure.action.UserConnected");
i.putExtra("username", user);
i.putExtra("email", email);
i.putExtra("session", newSessionId);
this.sendBroadcast(v1);
解決策 (可能なら):
Intent i = new Intent();
i.setAction("com.secure.action.UserConnected");
sendBroadcast(v1);
設定 (レシーバー)[1] 出典: StackOverflow:
<manifest ...>
<!-- Permission declaration -->
<permission android:name="my.app.PERMISSION" />
<receiver
android:name="my.app.BroadcastReceiver"
android:permission="com.secure.PERMISSION"> <!-- Permission enforcement -->
<intent-filter>
<action android:name="com.secure.action.UserConnected" />
</intent-filter>
</receiver>
...
</manifest>
設定 (レシーバー)[1] 出典: StackOverflow:
<manifest>
<!-- We declare we own the permission to send broadcast to the above receiver -->
<uses-permission android:name="my.app.PERMISSION" />
</manifest>
参考文献
CERT: DRD03-J. Do not broadcast sensitive information using an implicit intent
Android Official Doc: BroadcastReceiver (Security)
Android Official Doc: Receiver configuration (see android:permission
)
[1] StackOverflow: How to set permissions in broadcast sender and receiver in android
CWE-925: Improper Verification of Intent by Broadcast Receiver
CWE-927: Use of Implicit Intent for Sensitive Communication
ワールドライタブルファイル (Android)
このコンテキストで書き込まれたファイルは、作成モード MODE_WORLD_READABLE
を使用しています。
これは、書き込まれたコンテンツを露呈することが期待された動作ではないかもしれません。
リスクのあるコード:
fos = openFileOutput(filename, MODE_WORLD_READABLE);
fos.write(userInfo.getBytes());
解決策 (MODE_PRIVATE を用いた):
fos = openFileOutput(filename, MODE_PRIVATE);
解決策 (ローカル SQLite データベースを用いた):
ローカル SQLite データベースを使用することが、おそらく構造化データを格納するための最適なソリューションです。
データベースファイルが外部ストレージに作成されていないことを確認してください。実装ガイドラインについては、下記の参考文献を参照してください。
参考文献
CERT: DRD11-J. Ensure that sensitive data is kept secure
Android Official Doc: Security Tips
Android Official Doc: Context.MODE_PRIVATE
vogella.com: Android SQLite database and content provider - Tutorial
OWASP Mobile Top 10 2014-M2: Insecure Data Storage
CWE-312: Cleartext Storage of Sensitive Information
ジオロケーションが作動した WebView (Android)
その地理位置情報の取得についてユーザーに確認を求めることをお勧めします。
リスクのあるコード:
webView.setWebChromeClient(new WebChromeClient() {
@Override
public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
callback.invoke(origin, true, false);
}
});
推奨するコード:
地理位置情報のサンプリングを制限し、ユーザーに確認を求める。
webView.setWebChromeClient(new WebChromeClient() {
@Override
public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
callback.invoke(origin, true, false);
//ユーザーに確認を求める
}
});
参考文献
CERT: DRD15-J. Consider privacy concerns when using Geolocation API
Wikipedia: W3C Geolocation API
W3C: Geolocation Specification
JavaScript が使用可能な WebView (Android)
WebView に対して JavaScript を有効にすることは、直ちに XSS の影響を受けやすくなることを意味します。
潜在的な反射型 XSS や格納型 XSS 、 DOM ベース XSS のためにページレンダリングを検査する必要があります。
WebView myWebView = (WebView) findViewById(R.id.webView);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
リスクのあるコード:
JavaScript を有効にすることは悪い習慣ではありません。これは、バックエンドのコードは XSS の可能性が監査される必要があること意味しています。
DOM ベース XSS が原因でクライアント側でも XSS が取り込まれる可能性があります。
function updateDescription(newDescription) {
$("#userDescription").html(""+newDescription+"
");
}
参考文献
Issue: Using setJavaScriptEnabled can introduce XSS vulnerabilities
Android Official Doc: WebView
WASC-8: Cross Site Scripting
OWASP: XSS Prevention Cheat Sheet
OWASP: Top 10 2013-A3: Cross-Site Scripting (XSS)
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Javascript インタフェースを備える WebView (Android)
JavaScript インタフェースの使用は、 WebView を危険な API にさらす可能性があります。 XSS が WebView でトリガーの場合、そのクラスは悪意のある JavaScript コードによって呼び出される可能性があります。
リスクのあるコード:
WebView myWebView = (WebView) findViewById(R.id.webView);
myWebView.addJavascriptInterface(new FileWriteUtil(this), "fileWriteUtil");
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
[...]
class FileWriteUtil {
Context mContext;
FileOpenUtil(Context c) {
mContext = c;
}
public void writeToFile(String data, String filename, String tag) {
[...]
}
}
参考文献
Android Official Doc: WebView.addJavascriptInterface()
CWE-749: Exposed Dangerous Method or Function