Table of Contents
- 予測可能な擬似乱数生成器 (PREDICTABLE_RANDOM)
- 予測可能な擬似乱数生成器 (Scala) (PREDICTABLE_RANDOM_SCALA)
- 信頼できないサーブレットパラメーター (SERVLET_PARAMETER)
- 信頼できない Content-Type ヘッダー (SERVLET_CONTENT_TYPE)
- 信頼できない Host ヘッダー (SERVLET_SERVER_NAME)
- 信頼できないセッション Cookie の値 (SERVLET_SESSION_ID)
- 信頼できないクエリー文字列 (SERVLET_QUERY_STRING)
- 信頼できない HTTP ヘッダー (SERVLET_HEADER)
- 信頼できない Referer ヘッダー (SERVLET_HEADER_REFERER)
- 信頼できない User-Agent ヘッダー (SERVLET_HEADER_USER_AGENT)
- Cookie 内に機密データの可能性 (COOKIE_USAGE)
- 潜在的なパストラバーサル (ファイル読み出し) (PATH_TRAVERSAL_IN)
- 潜在的なパストラバーサル (ファイル書き込み) (PATH_TRAVERSAL_OUT)
- Scala API を使用した潜在的なパストラバーサル (ファイル読み出し) (SCALA_PATH_TRAVERSAL_IN)
- 潜在的なコマンドインジェクション (COMMAND_INJECTION)
- 潜在的なコマンドインジェクション (Scala) (SCALA_COMMAND_INJECTION)
- FilenameUtils は NULL バイトをフィルタリングしない (WEAK_FILENAMEUTILS)
- 任意の証明書を受け入れる TrustManager (WEAK_TRUST_MANAGER)
- 任意の署名付き証明書を受け入れる HostnameVerifier (WEAK_HOSTNAME_VERIFIER)
- JAX-WS SOAP エンドポイントを発見 (JAXWS_ENDPOINT)
- JAX-RS REST エンドポイントを発見 (JAXRS_ENDPOINT)
- Tapestry ページを発見 (TAPESTRY_ENDPOINT)
- Wicket ページを発見 (WICKET_ENDPOINT)
- MD2,MD4,MD5 は弱いハッシュ関数 (WEAK_MESSAGE_DIGEST_MD5)
- SHA-1 は弱いハッシュ関数 (WEAK_MESSAGE_DIGEST_SHA1)
- デフォルトのコンストラクターを持つ DefaultHttpClient は TLS 1.2 と互換性がない (DEFAULT_HTTP_CLIENT)
- 弱い SSLContext (SSL_CONTEXT)
- 独自メッセージダイジェスト (CUSTOM_MESSAGE_DIGEST)
- 汚染されたファイル名の読み取り (FILE_UPLOAD_FILENAME)
- 正規表現による DoS (ReDoS) (REDOS)
- XXE に脆弱な XML 解析 (XMLStreamReader) (XXE_XMLSTREAMREADER)
- XXE に脆弱な XML 解析 (XPathExpression) (XXE_XPATH)
- XXE に脆弱な XML 解析 (SAXParser) (XXE_SAXPARSER)
- XXE に脆弱な XML 解析 (XMLReader) (XXE_XMLREADER)
- XXE に脆弱な XML 解析 (DocumentBuilder) (XXE_DOCUMENT)
- XXE に脆弱な XML 解析 (TransformerFactory) (XXE_DTD_TRANSFORM_FACTORY)
- XXE に脆弱な XSLT 解析 (TransformerFactory) (XXE_XSLT_TRANSFORM_FACTORY)
- 潜在的な XPath インジェクション (XPATH_INJECTION)
- Struts 1 アクション を発見 (STRUTS1_ENDPOINT)
- Struts 2 のエンドポイントを発見 (STRUTS2_ENDPOINT)
- Spring のエンドポイントを発見 (SPRING_ENDPOINT)
- Spring CSRF 保護の無効化 (SPRING_CSRF_PROTECTION_DISABLED)
- Spring の制限のない RequestMapping による CSRF (SPRING_CSRF_UNRESTRICTED_REQUEST_MAPPING)
- 潜在的インジェクション (独自) (CUSTOM_INJECTION)
- 潜在的な SQL インジェクション (SQL_INJECTION)
- Turbine による潜在的な SQL インジェクション (SQL_INJECTION_TURBINE)
- 潜在的な SQL/HQL インジェクション (Hibernate) (SQL_INJECTION_HIBERNATE)
- 潜在的な SQL/JDOQL インジェクション (JDO) (SQL_INJECTION_JDO)
- 潜在的な SQL/JPQL インジェクション (JPA) (SQL_INJECTION_JPA)
- 潜在的な JDBC インジェクション (Spring JDBC) (SQL_INJECTION_SPRING_JDBC)
- 潜在的な JDBC インジェクション (SQL_INJECTION_JDBC)
- 潜在的な Scala Slick インジェクション (SCALA_SQL_INJECTION_SLICK)
- 潜在的な Scala Anorm インジェクション (SCALA_SQL_INJECTION_ANORM)
- 潜在的な Android SQL インジェクション (SQL_INJECTION_ANDROID)
- 潜在的な LDAP インジェクション (LDAP_INJECTION)
- スクリプトエンジン使用時の潜在的なコードインジェクション (SCRIPT_ENGINE_INJECTION)
- Spring 式使用時の潜在的なコードインジェクション (SPEL_INJECTION)
- 式言語 (EL) 使用時の潜在的なコードインジェクション (EL_INJECTION)
- Seam ロギング呼び出しでの潜在的なコードインジェクション (SEAM_LOG_INJECTION)
- OGNL 式使用時の潜在的なコードインジェクション (OGNL_INJECTION)
- 潜在的な HTTP レスポンス分割 (HTTP_RESPONSE_SPLITTING)
- ログの潜在的な CRLF インジェクション (CRLF_INJECTION_LOGS)
- 潜在的な構成の外部制御 (EXTERNAL_CONFIG_CONTROL)
- 不正な16進数の連結 (BAD_HEXA_CONVERSION)
- Hazelcast 対称暗号 (HAZELCAST_SYMMETRIC_ENCRYPTION)
- NullCipher は安全でない (NULL_CIPHER)
- 暗号化されていないソケット (UNENCRYPTED_SOCKET)
- 暗号化されていないサーバーソケット (UNENCRYPTED_SERVER_SOCKET)
- DES は安全でない (DES_USAGE)
- DESede は安全でない (TDES_USAGE)
- パディングなしの RSA 暗号は安全でない (RSA_NO_PADDING)
- ハードコードされたパスワード (HARD_CODE_PASSWORD)
- ハードコードされた鍵 (HARD_CODE_KEY)
- 安全でないハッシュの比較 (UNSAFE_HASH_EQUALS)
- 入力検証がない Struts フォーム (STRUTS_FORM_VALIDATION)
- XSSRequestWrapper は弱い XSS 保護 (XSS_REQUEST_WRAPPER)
- 短い鍵での Blowfish の使用 (BLOWFISH_KEY_SIZE)
- 短い鍵長での RSA の使用 (RSA_KEY_SIZE)
- 未検証のリダイレクト (UNVALIDATED_REDIRECT)
- 未検証のリダイレクト (Play Framework) (PLAY_UNVALIDATED_REDIRECT)
- 未検証のリダイレクト (Spring アプリケーション) (SPRING_UNVALIDATED_REDIRECT)
- 予期しないプロパティ漏洩 (ENTITY_LEAK)
- 一括割り当て (ENTITY_MASS_ASSIGNMENT)
- 動的 JSP インクルード (JSP_INCLUDE)
- Spring 式の動的変数 (JSP_SPRING_EVAL)
- 特別な XML 文字のエスケープが無効 (JSP_JSTL_OUT)
- JSP 内の潜在的な XSS (XSS_JSP_PRINT)
- サーブレット内の潜在的な XSS (XSS_SERVLET)
- XMLDecoder の使用 (XML_DECODER)
- 静的な初期化ベクトル (Static IV) (STATIC_IV)
- ECB モードは安全でない (ECB_MODE)
- パディングオラクル攻撃の影響を受けやすい暗号 (PADDING_ORACLE)
- 整合性のない暗号 (CIPHER_INTEGRITY)
- ESAPI Encryptor の使用 (ESAPI_ENCRYPTOR)
- 外部ファイルアクセス (Android) (ANDROID_EXTERNAL_FILE_ACCESS)
- ブロードキャスト (Android) (ANDROID_BROADCAST)
- ワールドライタブルファイル (Android) (ANDROID_WORLD_WRITABLE)
- ジオロケーションがアクティブ化された WebView (Android) (ANDROID_GEOLOCATION)
- JavaScript を有効にした WebView (Android) (ANDROID_WEB_VIEW_JAVASCRIPT)
- JavaScript インタフェースがある WebView (Android) (ANDROID_WEB_VIEW_JAVASCRIPT_INTERFACE)
- Secure フラグがない Cookie (INSECURE_COOKIE)
- HttpOnly フラグがない Cookie (HTTPONLY_COOKIE)
- オブジェクトデシリアライズの使用 (OBJECT_DESERIALIZATION)
- 安全でない Jackson のデシリアライズ設定 (JACKSON_UNSAFE_DESERIALIZATION)
- デシリアライゼーションガジェットとして使用できるクラス (DESERIALIZATION_GADGET)
- Trust Boundary Violation (TRUST_BOUNDARY_VIOLATION)
- 悪意のある XSLT が JSP タグに提供される可能性 (JSP_XSLT)
- 悪意のある XSLT が提供される可能性 (MALICIOUS_XSLT)
- Scala Play における潜在的な情報漏洩 (SCALA_SENSITIVE_DATA_EXPOSURE)
- Scala Play Server-Side Request Forgery (SSRF) (SCALA_PLAY_SSRF)
- URLConnection Server-Side Request Forgery (SSRF) と File Disclosure (URLCONNECTION_SSRF_FD)
- Scala Twirl テンプレートエンジンの潜在的な XSS (SCALA_XSS_TWIRL)
- Scala MVC API エンジンの潜在的な XSS (SCALA_XSS_MVC_API)
- Velocity の潜在的なテンプレートインジェクション (TEMPLATE_INJECTION_VELOCITY)
- Freemarker の潜在的なテンプレートインジェクション (TEMPLATE_INJECTION_FREEMARKER)
- Pebble の潜在的なテンプレートインジェクション (TEMPLATE_INJECTION_PEBBLE)
- 過剰に許可された CORS ポリシー (PERMISSIVE_CORS)
- 匿名 LDAP バインド (LDAP_ANONYMOUS)
- LDAP Entry Poisoning (LDAP_ENTRY_POISONING)
- 永続的 Cookie の使用 (COOKIE_PERSISTENT)
- URL を書き換えるメソッド (URL_REWRITING)
- 安全でない SMTP SSL 接続 (INSECURE_SMTP_SSL)
- AWS Query インジェクション (AWS_QUERY_INJECTION)
- JavaBeans プロパティインジェクション (BEAN_PROPERTY_INJECTION)
- Struts File Disclosure (STRUTS_FILE_DISCLOSURE)
- Spring File Disclosure (SPRING_FILE_DISCLOSURE)
- RequestDispatcher File Disclosure (REQUESTDISPATCHER_FILE_DISCLOSURE)
- 書式文字列操作 (FORMAT_STRING_MANIPULATION)
- HTTP Parameter Pollution (HTTP_PARAMETER_POLLUTION)
- エラーメッセージによる情報漏洩 (INFORMATION_EXPOSURE_THROUGH_AN_ERROR_MESSAGE)
- SMTP ヘッダーインジェクション (SMTP_HEADER_INJECTION)
- 有効なApache XML RPC サーバーまたはクライアントの拡張機能 (RPC_ENABLED_EXTENSIONS)
- HTMLエスケープを無効にすると,アプリケーションが XSS の危険にさらされる (WICKET_XSS1)
- SAML で XML コメントを無視すると,認証バイパスが発生する可能性がある (SAML_IGNORE_COMMENTS)
- 過剰に許可されたファイルパーミッション (OVERLY_PERMISSIVE_FILE_PERMISSION)
予測可能な擬似乱数生成器
Bug Pattern: PREDICTABLE_RANDOM
セキュリティ上重要なコンテキストで,予測可能な乱数が使用されると脆弱性につながることがあります。たとえば,その乱数が次のように使用されたときです。
- CSRF トークン:予測可能なトークンは,攻撃者がトークンの価値を知ることになるので,CSRF 攻撃につながる可能性がある
- パスワードリセットトークン(電子メールで送信):予測可能なパスワードトークンは,攻撃者が「パスワード変更」フォームのURLを推測するため,アカウントの乗っ取りにつながる可能性がある
- その他の秘密の値
手っ取り早い解決策は 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 (https://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)
予測可能な擬似乱数生成器 (Scala)
Bug Pattern: PREDICTABLE_RANDOM_SCALA
セキュリティ上重要なコンテキストで,予測可能な乱数が使用されると脆弱性につながることがあります。たとえば,その乱数が次のように使用されたときです。
- CSRF トークン:予測可能なトークンは,攻撃者がトークンの価値を知ることになるので,CSRF 攻撃につながる可能性がある
- パスワードリセットトークン(電子メールで送信):予測可能なパスワードトークンは,攻撃者が「パスワード変更」フォームのURLを推測するため,アカウントの乗っ取りにつながる可能性がある
- その他の秘密の値
手っ取り早い解決策は java.util.Random
の使用を java.security.SecureRandom などのより強固なものに置き換えることです。
脆弱なコード:
import scala.util.Random
def generateSecretToken() {
val result = Seq.fill(16)(Random.nextInt)
return result.map("%02x" format _).mkString
}
解決策:
import java.security.SecureRandom
def generateSecretToken() {
val rand = new SecureRandom()
val value = Array.ofDim[Byte](16)
rand.nextBytes(value)
return value.map("%02x" format _).mkString
}
参考文献
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)
信頼できないサーブレットパラメーター
Bug Pattern: SERVLET_PARAMETER
サーブレットは,さまざまなメソッドから GET と POST のパラメーターを読むことができます。取得した値は安全でないと考えるべきです。 次のような気密性の高い API に値を渡す前に,値を検証またはエスケープする必要があるかもしれません。
- SQL クエリー (SQL インジェクションにつながる可能性)
- ファイルオープン (パストラバーサルにつながる可能性)
- コマンド実行 (潜在的なコマンドインジェクション)
- HTMLの組み立て (潜在的な XSS)
- など...
参考文献
CWE-20: Improper Input Validation
信頼できない Content-Type ヘッダー
Bug Pattern: SERVLET_CONTENT_TYPE
HTTP ヘッダー Content-Type は,クライアントによって操作可能です。したがって,その値をセキュリティ上重要な決定では使用しないでください。
参考文献
CWE-807: Untrusted Inputs in a Security Decision
信頼できない Host ヘッダー
Bug Pattern: SERVLET_SERVER_NAME
Hostname ヘッダーは,クライアントによって操作可能です。したがって,その値をセキュリティ上重要な決定では使用しないでください。
ServletRequest.getServerName()
と HttpServletRequest.getHeader("Host")
は,どちらも Host
ヘッダーを抽出するという同じ動作をします。
GET /testpage HTTP/1.1
Host: www.example.com
[...]
アプリケーションにサービスを提供するウェブコンテナは,デフォルトでは,アプリケーションにリクエストをリダイレクトすることがあります。 これにより,悪意のあるユーザーが Host ヘッダーで任意の値を配置できるようになります。 リクエストに関して行うセキュリティ上の決定において,この値を信頼しないことをお勧めします。
参考文献
CWE-807: Untrusted Inputs in a Security Decision
信頼できないセッション Cookie の値
Bug Pattern: SERVLET_SESSION_ID
メソッド HttpServletRequest.getRequestedSessionId()
は,
通常,Cookie 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
信頼できないクエリー文字列
Bug Pattern: SERVLET_QUERY_STRING
クエリー文字列は,GET パラメーターの名前と値を連結したものです。意図したパラメーター以外を渡すことができます。
URL リクエストが /app/servlet.htm?a=1&b=2
のときは,クエリー文字列を抜き出すと a=1&b=2
になります。
HttpServletRequest.getParameter()
のようなメソッドで取得した個々のパラメーター値と同じように,HttpServletRequest.getQueryString()
から取得した値は安全でないと見なすべきです。
気密性の高い API に渡す前に,クエリー文字列から取得したものを検証またはエスケープする必要があります。
参考文献
CWE-20: Improper Input Validation
信頼できない HTTP ヘッダー
Bug Pattern: SERVLET_HEADER
リクエストヘッダーはリクエストしているユーザーによって容易に改ざんできます。 一般的には,ブラウザーからリクエストが攻撃者によって変更されることなく来ることを仮定すべきではありません。 このように,リクエストに関して行うあらゆるセキュリティ上の決定において,その値を信頼しないことをお勧めします。
参考文献
CWE-807: Untrusted Inputs in a Security Decision
信頼できない Referer ヘッダー
Bug Pattern: SERVLET_HEADER_REFERER
動作:
- リクエストが悪意のあるユーザーから来ているなら,任意の値をこのヘッダーに割り当てられる
- リクエストが安全 (HTTPS) である別のオリジンから開始されたときは,"Referer" は存在しない
推奨:
- このヘッダーの値に基づいてアクセス制御を行うべきではない
- CSRF 保護は,この値にだけ基づいて行われるべきではない (オプションなので)
参考文献
CWE-807: Untrusted Inputs in a Security Decision
信頼できない User-Agent ヘッダー
Bug Pattern: SERVLET_HEADER_USER_AGENT
ヘッダー "User-Agent" は,クライアントによって容易に偽装できます。User-Agent に基づいて (クローラー UA に対して) 異なった動作をすることは推奨できません。
参考文献
CWE-807: Untrusted Inputs in a Security Decision
Cookie 内に機密データの可能性
Bug Pattern: COOKIE_USAGE
カスタム Cookie に格納する情報は,機密やセッションに関連してはいけません。ほとんどの場合,機密データはセッションだけに格納して,ユーザーのセッション Cookie によってだけ参照されるべきです。
HttpSession (HttpServletRequest.getSession()
) を参照してください。
カスタム Cookie は,特定のセッションから独立した,より長く存続する必要がある情報のために使用できます。
参考文献
CWE-315: Cleartext Storage of Sensitive Information in a Cookie
潜在的なパストラバーサル (ファイル読み出し)
Bug Pattern: PATH_TRAVERSAL_IN
内容を読むためにファイルが開かれています。ファイル名は 入力 パラメーターに由来しています。 フィルターされていないパラメーターがこのファイル API に渡されると,ファイルシステムの任意の場所からファイルを読み出せるかもしれません。
このルールは 潜在的な パストラバーサルの脆弱性を特定します。多くの場合,構築されたファイルパスはユーザーが制御できません。 その場合,報告された事例は誤検出です。
脆弱なコード:
@GET
@Path("/images/{image}")
@Produces("images/*")
public Response getImage(@javax.ws.rs.PathParam("image") String image) {
File file = new File("resources/images/", image); //Weak point
if (!file.exists()) {
return Response.status(Status.NOT_FOUND).build();
}
return Response.ok().entity(new FileInputStream(file)).build();
}
解決策:
import org.apache.commons.io.FilenameUtils;
@GET
@Path("/images/{image}")
@Produces("images/*")
public Response getImage(@javax.ws.rs.PathParam("image") String image) {
File file = new File("resources/images/", FilenameUtils.getName(image)); //Fix
if (!file.exists()) {
return Response.status(Status.NOT_FOUND).build();
}
return Response.ok().entity(new FileInputStream(file)).build();
}
参考文献
WASC: Path Traversal
OWASP: Path Traversal
CAPEC-126: Path Traversal
CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
潜在的なパストラバーサル (ファイル書き込み)
Bug Pattern: PATH_TRAVERSAL_OUT
内容を書くためにファイルが開かれています。ファイル名は 入力 パラメーターに由来しています。 フィルターされていないパラメーターがこのファイル 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')
Scala API を使用した潜在的なパストラバーサル (ファイル読み出し)
Bug Pattern: SCALA_PATH_TRAVERSAL_IN
内容を読むためにファイルが開かれています。ファイル名は 入力 パラメーターに由来しています。 フィルターされていないパラメーターがこのファイル API に渡されると,ファイルシステムの任意の場所からファイルを読み出せるかもしれません。
このルールは 潜在的な パストラバーサルの脆弱性を特定します。多くの場合,構築されたファイルパスはユーザーが制御できません。 その場合,報告された事例は誤検出です。
脆弱なコード:
def getWordList(value:String) = Action {
if (!Files.exists(Paths.get("public/lists/" + value))) {
NotFound("File not found")
} else {
val result = Source.fromFile("public/lists/" + value).getLines().mkString // 弱点
Ok(result)
}
}
解決策:
import org.apache.commons.io.FilenameUtils;
def getWordList(value:String) = Action {
val filename = "public/lists/" + FilenameUtils.getName(value)
if (!Files.exists(Paths.get(filename))) {
NotFound("File not found")
} else {
val result = Source.fromFile(filename).getLines().mkString // 修正
Ok(result)
}
}
参考文献
WASC: Path Traversal
OWASP: Path Traversal
CAPEC-126: Path Traversal
CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
潜在的なコマンドインジェクション
Bug Pattern: COMMAND_INJECTION
強調表示された API は,システムコマンドを実行するために使用されています。 フィルタされていない入力がこの API に渡されると,任意のコマンド実行につながる可能性があります。
脆弱なコード:
import java.lang.Runtime;
Runtime r = Runtime.getRuntime();
r.exec("/bin/sh -c some_tool" + input);
参考文献
OWASP: Command Injection
OWASP: Top 10 2013-A1-Injection
CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
潜在的なコマンドインジェクション (Scala)
Bug Pattern: SCALA_COMMAND_INJECTION
強調表示された API は,システムコマンドを実行するために使用されています。 フィルタされていない入力がこの API に渡されると,任意のコマンド実行につながる可能性があります。
脆弱なコード:
def executeCommand(value:String) = Action {
val result = value.!
Ok("Result:\n"+result)
}
参考文献
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 バイトをフィルタリングしない
Bug Pattern: WEAK_FILENAMEUTILS
FilenameUtils'
メソッドの中には,NULLバイト (0x00
) をフィルタしないものもあります。
NULL バイトがファイル名に挿入され,そのファイル名が OS に渡されると取得されるファイルは NULL バイトより前に指定されたファイル名になります。
OS レベルであるので,たとえ Java 自体が NULLl バイトを気にしたり特別扱いをしなくても,すべての文字列が NULL バイトで終了するためです。
この OS の動作は,ファイル名の検証を「ファイル名の末尾 (たとえば,末尾が ".log"
であるか) を調べ,アクセスしても安全なファイルであるかを確認」といった具合にしていると回避されてしまうことがあります。
これを修正するためには,次の2つのことが推奨されています:
- Java 7 update 40 以降,または Java 8 以上へのアップグレード NNULL バイトインジェクションはそれらのバージョンで修正されている
- 信頼できないユーザーによって与えられた任意のファイル名が有効であることを確認するため,入念に検証する (すなわち,null が含まれていないか,パス文字が加えられていないかなど)
NULL バイトインジェクションの影響を受けない最新版の Java を使用していることがわかっているなら,このルールを無効にできます。
参考文献
WASC-28: Null Byte Injection
CWE-158: Improper Neutralization of Null Byte or NUL Character
任意の証明書を受け入れる TrustManager
Bug Pattern: WEAK_TRUST_MANAGER
空の TrustManager
実装は,多くの場合,
ルート 認証局 によって署名されていないホストに簡単に接続するために使用されます。
結果として,クライアントがどの証明書も信頼してしまうので,
中間者攻撃 (Man-in-the-middle attacks) に対して脆弱です。
(たとえば,TrustStore に基づいて) 特定の証明書を許可する TrustManager を構築すべきです。 適切な実装の詳細については: [1] [2]
脆弱なコード:
class TrustAllManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
//Trust any client connecting (no certificate validation)
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
//Trust any remote server (no certificate validation)
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
解決策 (キーストアに基づく TrustMangager):
KeyStore ks = //Load keystore containing the certificates trusted
SSLContext sc = SSLContext.getInstance("TLS");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ks);
sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(),null);
参考文献
WASC-04: Insufficient Transport Layer Protection
CWE-295: Improper Certificate Validation
任意の署名付き証明書を受け入れる HostnameVerifier
Bug Pattern: WEAK_HOSTNAME_VERIFIER
任意のホストを受け入れる HostnameVerifier
は,多くのホストで証明書を再利用するためによく使用されます。
結果として,クライアントがどの証明書も信頼してしまうので,これは 中間者攻撃 (Man-in-the-middle attacks) に対して脆弱です。
(たとえば,TrustStore に基づいて) 特定の証明書を許可する TrustManager を構築すべきです。 複数のサブドメインで再利用するためのワイルドカード証明書を作成すべきです。 適切な実装の詳細については: [1] [2]
脆弱なコード:
public class AllHosts implements HostnameVerifier {
public boolean verify(final String hostname, final SSLSession session) {
return true;
}
}
解決策 (キーストアに基づく TrustMangager):
KeyStore ks = //Load keystore containing the certificates trusted
SSLContext sc = SSLContext.getInstance("TLS");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ks);
sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(),null);
参考文献
WASC-04: Insufficient Transport Layer Protection
CWE-295: Improper Certificate Validation
JAX-WS SOAP エンドポイントを発見
Bug Pattern: JAXWS_ENDPOINT
このメソッドは,SOAP Web サービス (JSR224) の一部です。
この Web サービスの安全性を分析するべきです。たとえば:
- 認証を強制したときはテストすべき
- アクセス制御を強制したときはテストすべき
- 潜在的な脆弱性のために入力を追跡すべき
- 通信は理想的には SSL の上で行うべき
参考文献
OWASP: Web Service Security Cheat Sheet
CWE-20: Improper Input Validation
JAX-RS REST エンドポイントを発見
Bug Pattern: JAXRS_ENDPOINT
このメソッドは REST Web サービス (JSR311) の一部です。
この Web サービスの安全性を分析するべきです。たとえば:
- 認証を強制したときはテストすべき
- アクセス制御を強制したときはテストすべき
- 潜在的な脆弱性のために入力を追跡すべき
- 通信は理想的には SSL の上で行うべき
- サービスが書き込み (POSTなど) をサポートしているときは,CSRF に対する脆弱性を調査すべき
参考文献
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 ページを発見
Bug Pattern: TAPESTRY_ENDPOINT
アプリケーション起動時に 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 ページを発見
Bug Pattern: WICKET_ENDPOINT
このクラスは,Wicket WebPage を表します。入力はコンストラクターに渡された PageParameters インスタンスから自動的に読み出されます。
現在のページは,ビュー /package/WebPageName.html
にマッピングされます。
このアプリケーションの各 Wicket ページは,このように自動的にマッピングされるすべての入力を使用される前に適切に検証されているか調査すべきです。
参考文献
Apache Wicket Home Page
CWE-20: Improper Input Validation
MD2,MD4,MD5 は弱いハッシュ関数
Bug Pattern: WEAK_MESSAGE_DIGEST_MD5
アルゴリズム MD2,MD4,MD5 は推奨されているメッセージダイジェストではありません。 PBKDF2 (Password-Based Key Derivation Function 2) は,たとえばパスワードをハッシュ化するために使用すべきです。
「MD5 ハッシュ関数のセキュリティは深刻に損なわれています。 2.6 GHz Pentium 4 プロセッサー (複雑さは 224.1) のコンピューターで数秒で衝突を見つけられる衝突攻撃が存在します。[1] さらに,既製のコンピューティングハードウェア (複雑さは 239) を使用して,数時間以内に指定されたプレフィックスを持つ2つの入力の衝突を生成する選択プリフィックス衝突攻撃もあります。[2]」
- Wikipedia: MD5 - Security
「SHA-224,SHA-256,SHA-384,SHA-512,SHA-512/224,SHA-512/256:
これらのハッシュ関数の使用は,すべてのハッシュ関数アプリケーションで許容されています。」
- NIST: Transitioning the Use of Cryptographic Algorithms and Key Lengths p.15
「PBKDF (Password-Based Key Derivation Function) の主な考え方は,各パスワードをテストするために必要な時間を増やすことによって,パスワードに対する辞書攻撃またはブルートフォース攻撃を遅延させることです。 もっともらしいパスワードのリストを持つ攻撃者は,既知の反復カウンタと salt を使用して PBKDF を評価できます。 攻撃者は試行ごとにかなりの計算時間を費やさなければならないので,辞書攻撃やブルートフォース攻撃を適用するのが難しくなります。」
- NIST: Recommendation for Password-Based Key Derivation p.12
脆弱なコード:
MessageDigest md5Digest = MessageDigest.getInstance("MD5");
md5Digest.update(password.getBytes());
byte[] hashValue = md5Digest.digest();
byte[] hashValue = DigestUtils.getMd5Digest().digest(password.getBytes());
解決策 (Bouncy Castle を使う):
public static byte[] getEncryptedPassword(String password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(new SHA256Digest());
gen.init(password.getBytes("UTF-8"), salt.getBytes(), 4096);
return ((KeyParameter) gen.generateDerivedParameters(256)).getKey();
}
解決策 (Java 8 以降):
public static byte[] getEncryptedPassword(String password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 4096, 256 * 8);
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
return f.generateSecret(spec).getEncoded();
}
参考文献
[1] On Collisions for MD5: Master Thesis by M.M.J. Stevens
[2] Chosen-prefix collisions for MD5 and applications: Paper written by Marc Stevens
Wikipedia: MD5
NIST: Transitioning the Use of Cryptographic Algorithms and Key Lengths
NIST: Recommendation for Password-Based Key Derivation
Stackoverflow: Reliable implementation of PBKDF2-HMAC-SHA256 for Java
CWE-327: Use of a Broken or Risky Cryptographic Algorithm
SHA-1 は弱いハッシュ関数
Bug Pattern: WEAK_MESSAGE_DIGEST_SHA1
アルゴリズム SHA-1 は,ハッシュパスワード,署名検証などのために推奨されるアルゴリズムではありません。 PBKDF2 (Password-Based Key Derivation Function 2) は,たとえばパスワードをハッシュ化するために使用すべきです。
「デジタル署名生成用の SHA-1:
SHA-1は,NIST プロトコル仕様ガイダンスで特に許可されているデジタル署名の生成にだけ使用できます。 他のすべてのアプリケーションでは,SHA-1 をデジタル署名の生成に使用してはいけません。
デジタル署名検証用の SHA-1:
デジタル署名検証では,SHA-1 は従来の使用が許可されています。
[...]
SHA-224,SHA-256,SHA-384,SHA-512,SHA-512/224,SHA-512/256:
これらのハッシュ関数の使用は,すべてのハッシュ関数アプリケーションで許容されています。」
- NIST: Transitioning the Use of Cryptographic Algorithms and Key Lengths p.15
「PBKDF (Password-Based Key Derivation Function) の主な考え方は,各パスワードをテストするために必要な時間を増やすことによって,パスワードに対する辞書攻撃またはブルートフォース攻撃を遅延させることです。 もっともらしいパスワードのリストを持つ攻撃者は,既知の反復カウンタと salt を使用して PBKDF を評価できます。 攻撃者は試行ごとにかなりの計算時間を費やさなければならないので,辞書攻撃やブルートフォース攻撃を適用するのが難しくなります。」
- NIST: Recommendation for Password-Based Key Derivation p.12
脆弱なコード:
MessageDigest sha1Digest = MessageDigest.getInstance("SHA1");
sha1Digest.update(password.getBytes());
byte[] hashValue = sha1Digest.digest();
byte[] hashValue = DigestUtils.getSha1Digest().digest(password.getBytes());
解決策 (Bouncy Castle を使う):
public static byte[] getEncryptedPassword(String password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(new SHA256Digest());
gen.init(password.getBytes("UTF-8"), salt.getBytes(), 4096);
return ((KeyParameter) gen.generateDerivedParameters(256)).getKey();
}
解決策 (Java 8 以降):
public static byte[] getEncryptedPassword(String password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 4096, 256 * 8);
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
return f.generateSecret(spec).getEncoded();
}
参考文献
Qualys blog: SHA1 Deprecation: What You Need to Know
Google Online Security Blog: Gradually sunsetting SHA-1
NIST: Transitioning the Use of Cryptographic Algorithms and Key Lengths
NIST: Recommendation for Password-Based Key Derivation
Stackoverflow: Reliable implementation of PBKDF2-HMAC-SHA256 for Java
CWE-327: Use of a Broken or Risky Cryptographic Algorithm
デフォルトのコンストラクターを持つ DefaultHttpClient は TLS 1.2 と互換性がない
Bug Pattern: DEFAULT_HTTP_CLIENT
脆弱なコード:
HttpClient client = new DefaultHttpClient();
解決策:
推奨構成の1つを使用して,https.protocols
JVM オプションを TLSv1.2 を含むように設定して,実装を改良します:
- 代わりに SystemDefaultHttpClient を使用する
サンプルコード:
HttpClient client = new SystemDefaultHttpClient();
getSystemSocketFactory()
で SSLSocketFactory のインスタンスを取得して,HttpClient の作成に使用するgetSystemSocketFactory()
でインスタンスを取得して,HttpClient の作成に使用するbuild()
を呼び出す前に useSystemProperties()
を呼び出す
サンプルコード:
HttpClient client = HttpClientBuilder.create().useSystemProperties().build();
createSystem()
を呼び出してインスタンスを作成する
サンプルコード:
HttpClient client = HttpClients.createSystem();
参考文献
Diagnosing TLS, SSL, and HTTPS
弱い SSLContext
Bug Pattern: SSL_CONTEXT
脆弱なコード:
SSLContext.getInstance("SSL");
解決策:
https.protocols
JVM オプションを TLSv1.2を含むように設定して,実装を改良します:
SSLContext.getInstance("TLS");
参考文献
Diagnosing TLS, SSL, and HTTPS
独自メッセージダイジェスト
Bug Pattern: CUSTOM_MESSAGE_DIGEST
独自メッセージダイジェストの実装は間違いの元になりやすいです。
NIST は,SHA-224,SHA-256,SHA-384,SHA-512,SHA-512/224,SHA-512/256 の使用を推奨しています。
「デジタル署名生成用の SHA-1:
SHA-1は,NIST プロトコル仕様ガイダンスで特に許可されているデジタル署名の生成にだけ使用できます。 他のすべてのアプリケーションでは,SHA-1 をデジタル署名の生成に使用してはいけません。
デジタル署名検証用の SHA-1:
デジタル署名検証では,SHA-1 は従来の使用が許可されています。
[...]
SHA-224,SHA-256,SHA-384,SHA-512,SHA-512/224,SHA-512/256:
これらのハッシュ関数の使用は,すべてのハッシュ関数アプリケーションで許容されています。」
- NIST: Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths p.15
脆弱なコード:
MyProprietaryMessageDigest extends MessageDigest {
@Override
protected byte[] engineDigest() {
[...]
// 独創性は悪い考え
return [...];
}
}
承認されたアルゴリズムの1つを使用するように実装を改良します。セキュリティニーズを満たす十分に強いアルゴリズムを使用します。
解決例:
MessageDigest sha256Digest = MessageDigest.getInstance("SHA256");
sha256Digest.update(password.getBytes());
参考文献
NIST Approved Hash Functions
CWE-327: Use of a Broken or Risky Cryptographic Algorithm
汚染されたファイル名の読み取り
Bug Pattern: FILE_UPLOAD_FILENAME
FileUpload 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)
Bug Pattern: REDOS
正規表現 (Regex) は,DoS攻撃 (ReDoS と呼ばれる) の対象となることがよくあります。 これは,正規表現がどのように定義されているかに応じて,正規表現エンジンが特定の文字列を解析するときに長い時間がかかることが原因です。
たとえば,次の正規表現の場合: ^(a+)+$
,"aaaaaaaaaaaaaaaaX
" を入力すると正規表現エンジンは 65536 通りの異なるパスを解析します。
[1] OWASP リファレンスから抜粋した例
したがって,1回のリクエストでサーバー側で大量の計算が発生する可能性があります。
この正規表現 (およびその他同様のもの) に関連する問題は,括弧の内側にある +
(または *
) と括弧の外側にある +
(または *
) によって,同じ入力文字を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 解析 (XMLStreamReader)
Bug Pattern: XXE_XMLSTREAMREADER
攻撃
信頼されていないソースから受け取った XML を処理しているときに,XML パーサーが XML エンティティをサポートしていると XML 外部エンティティ (XXE:XML External Entity) 攻撃が発生する可能性があります。
リスク 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 パーサーの危険な機能が公開されないようにするためには,コードを次のように変更します。
脆弱なコード:
public void parseXML(InputStream input) throws XMLStreamException {
XMLInputFactory factory = XMLInputFactory.newFactory();
XMLStreamReader reader = factory.createXMLStreamReader(input);
[...]
}
次のスニペットでは,利用可能な2つの解決策を示しています。1つまたは両方の機能を設定します。
外部エンティティーを無効にする解決策:
public void parseXML(InputStream input) throws XMLStreamException {
XMLInputFactory factory = XMLInputFactory.newFactory();
factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
XMLStreamReader reader = factory.createXMLStreamReader(input);
[...]
}
DTD を無効にする解決策:
public void parseXML(InputStream input) throws XMLStreamException {
XMLInputFactory factory = XMLInputFactory.newFactory();
factory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
XMLStreamReader reader = factory.createXMLStreamReader(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
Identifying XML External Entity vulnerability (XXE)
JEP 185: Restrict Fetching of External XML Resources
XXE に脆弱な XML 解析 (XPathExpression)
Bug Pattern: XXE_XPATH
攻撃
信頼されていないソースから受け取った XML を処理しているときに,XML パーサーが XML エンティティをサポートしていると XXE (XML External Entity) 攻撃が発生する可能性があります。
リスク 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 builder = df.newDocumentBuilder();
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xpath = xPathFactory.newXPath();
XPathExpression xPathExpr = xpath.compile("/somepath/text()");
xPathExpr.evaluate(new InputSource(inputStream));
次のスニペットでは,利用可能な2つの解決策を示しています。1つまたは両方の機能を設定します。
"Secure processing" モードを使用した解決策:
この設定により,サービス拒否攻撃とリモートファイルアクセスから保護されます。
DocumentBuilderFactory df = DocumentBuilderFactory.newInstance();
df.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
DocumentBuilder builder = df.newDocumentBuilder();
[...]
xPathExpr.evaluate( builder.parse(inputStream) );
DTD を無効にする解決策:
DTD を無効にすることによって,ほとんどすべての XXE 攻撃 が防止されます。
DocumentBuilderFactory df = DocumentBuilderFactory.newInstance();
spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
DocumentBuilder builder = df.newDocumentBuilder();
[...]
xPathExpr.evaluate( builder.parse(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
Identifying XML External Entity vulnerability (XXE)
XML External Entity (XXE) Prevention Cheat Sheet
XXE に脆弱な XML 解析 (SAXParser)
Bug Pattern: XXE_SAXPARSER
攻撃
信頼されていないソースから受け取った XML を処理しているときに,XML パーサーが XML エンティティをサポートしていると XML 外部エンティティ (XXE:XML External Entity) 攻撃が発生する可能性があります。
リスク 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);
次のスニペットでは,利用可能な2つの解決策を示しています。1つまたは両方の機能を設定します。
"Secure processing" モードを使用した解決策:
この設定により,サービス拒否攻撃とリモートファイルアクセスから保護されます。
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
SAXParser parser = spf.newSAXParser();
parser.parse(inputStream, customHandler);
DTD を無効にする解決策:
DTD を無効にすることによって,ほとんどすべての XXE 攻撃 が防止されます。
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
Identifying XML External Entity vulnerability (XXE)
Xerces complete features list
XXE に脆弱な XML 解析 (XMLReader)
Bug Pattern: XXE_XMLREADER
攻撃
信頼されていないソースから受け取った XML を処理しているときに,XML パーサーが XML エンティティをサポートしていると XML 外部エンティティ (XXE:XML External Entity) 攻撃が発生する可能性があります。
リスク 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));
次のスニペットでは,利用可能な2つの解決策を示しています。1つまたは両方の機能を設定します。
"Secure processing" モードを使用した解決策:
この設定により,サービス拒否攻撃とリモートファイルアクセスから保護されます。
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
reader.setContentHandler(customHandler);
reader.parse(new InputSource(inputStream));
DTD を無効にする解決策:
DTD を無効にすることによって,ほとんどすべての XXE 攻撃 が防止されます。
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
Identifying XML External Entity vulnerability (XXE)
Xerces complete features list
XXE に脆弱な XML 解析 (DocumentBuilder)
Bug Pattern: XXE_DOCUMENT
攻撃
信頼されていないソースから受け取った XML を処理しているときに,XML パーサーが XML エンティティをサポートしていると XML 外部エンティティ (XXE:XML External Entity) 攻撃が発生する可能性があります。
リスク 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);
次のスニペットでは,利用可能な2つの解決策を示しています。1つまたは両方の機能を設定します。
"Secure processing" モードを使用した解決策:
この設定により,サービス拒否攻撃とリモートファイルアクセスから保護されます。
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(input);
DTD を無効にする解決策:
DTD を無効にすることによって,ほとんどすべての XXE 攻撃 が防止されます。
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
Identifying XML External Entity vulnerability (XXE)
Xerces2 complete features list
XXE に脆弱な XML 解析 (TransformerFactory)
Bug Pattern: XXE_DTD_TRANSFORM_FACTORY
攻撃
信頼されていないソースから受け取った XML を処理しているときに,XML パーサーが XML エンティティをサポートしていると XXE (XML External Entity) 攻撃が発生する可能性があります。
リスク 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 パーサーの危険な機能が公開されないようにするためには,コードを次のように変更します。
脆弱なコード:
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(input, result);
次のスニペットでは,利用可能な2つの解決策を示しています。1つまたは両方の機能を設定します。
"Secure processing" モードを使用した解決策:
This setting will protect you against remote file access but not denial of service.
TransformerFactory factory = TransformerFactory.newInstance();
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "all");
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "all");
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(input, result);
DTD を無効にする解決策:
This setting will protect you against remote file access but not denial of service.
TransformerFactory factory = TransformerFactory.newInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(input, result);
参考文献
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
Identifying XML External Entity vulnerability (XXE)
XXE に脆弱な XSLT 解析 (TransformerFactory)
Bug Pattern: XXE_XSLT_TRANSFORM_FACTORY
攻撃
信頼されていないソースから受け取った XSLT を処理しているときに,XSLT パーサーが 外部エンティティをサポートしていると XXE (XSLT External Entity) 攻撃が発生する可能性があります。
リスク: ローカルファイルの内容の暴露 (XXE: XML External Entity)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:value-of select="document('/etc/passwd')">
</xsl:value-of></xsl:template>
</xsl:stylesheet>
解決策
XML パーサーの危険な機能が公開されないようにするためには,コードを次のように変更します。
脆弱なコード:
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(input, result);
次のスニペットでは,利用可能な2つの解決策を示しています。1つまたは両方の機能を設定します。
"Secure processing" モードを使用した解決策:
この設定により,リモートファイルアクセスから保護されますが,サービス拒否は保護されません。
TransformerFactory factory = TransformerFactory.newInstance();
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "all");
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "all");
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(input, result);
DTD を無効にする解決策:
この設定により,リモートファイルアクセスから保護されますが,サービス拒否は保護されません。
TransformerFactory factory = TransformerFactory.newInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(input, result);
参考文献
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
Identifying XML External Entity vulnerability (XXE)
潜在的な XPath インジェクション
Bug Pattern: XPATH_INJECTION
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.net: XQuery Injection
Struts 1 アクション を発見
Bug Pattern: STRUTS1_ENDPOINT
このクラスは Struts 1 のアクションです。
リクエストがこのコントローラーにルーティングされると,HTTP パラメーター を含む Form オブジェクトが自動的にインスタンス化されます。 これらのパラメーターが安全に使用されているかを確認するためにレビューすべきです。
Struts 2 のエンドポイントを発見
Bug Pattern: STRUTS2_ENDPOINT
Struts 2 では,エンドポイントは Plain Old Java Objects (POJO) です。つまり,インタフェース/クラスを実装/継承する必要がないということです。
リクエストがそのコントローラー (選択されたクラス) にルーティングされると与えられた HTTP パラメーターが自動的にクラスのセッターにマッピングされます。 そのため,フォームにそれらの値が含まれていなくても,このクラスのすべてのセッターは信頼できない入力として見なすべきです。 オブジェクトにそのようなセッターがあるかぎり,攻撃者はリクエストに追加の値を与えるだけで,オブジェクトに設定できます。 これらのパラメーターが安全に使用されているかを確認するためにレビューすべきです。
Spring のエンドポイントを発見
Bug Pattern: SPRING_ENDPOINT
このクラスは Spring コントローラーです。
RequestMapping
(そのショートカットアノテーション GetMapping
,PostMapping
,PutMapping
,
DeleteMapping
,PatchMapping
) というアノテーションが付けられたすべてのメソッドは,リモートから到達可能です。
リモートに公開したメソッドが潜在的な攻撃者に公開しても安全であるかを確認するために,このクラスを分析するべきです。
Spring CSRF 保護の無効化
Bug Pattern: SPRING_CSRF_PROTECTION_DISABLED
Spring Security の CSRF 保護を無効にすることは,標準の Web アプリケーションでは安全ではありません。
この保護を無効にすることが有効なユースケースは,ブラウザー以外のクライアントによってだけ使用されることが保証されている状態変更操作を公開するサービスです。
安全でない設定:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
}
参考文献
Spring Security Official Documentation: When to use CSRF protection
OWASP: Cross-Site Request Forgery
OWASP: CSRF Prevention Cheat Sheet
CWE-352: Cross-Site Request Forgery (CSRF)
Spring の制限のない RequestMapping による CSRF
Bug Pattern: SPRING_CSRF_UNRESTRICTED_REQUEST_MAPPING
RequestMapping
というアノテーションが付けられたメソッドは,デフォルトですべての HTTP リクエストメソッドにマッピングされます。
しかし,Spring Security の CSRF 保護は HTTP リクエストメソッド GET
,HEAD
,TRACE
,OPTIONS
に対して有効になっていません (トークンが漏洩する可能性があるため)。
したがって,RequestMapping
でアノテーションされ,マッピングを絞り込まない状態変更メソッド
POST
,PUT
,DELETE
,PATCH
は CSRF 攻撃に対して脆弱です。
脆弱なコード:
@Controller
public class UnsafeController {
@RequestMapping("/path")
public void writeData() {
// このメソッド内で実行される状態変更操作
}
}
解決策 (Spring Framework 4.3 以降):
@Controller
public class SafeController {
/**
* For methods without side-effects use @GetMapping.
*/
@GetMapping("/path")
public String readData() {
// このメソッド内で状態変更操作は実行されない
return "";
}
/**
* For state-changing methods use either @PostMapping, @PutMapping, @DeleteMapping, or @PatchMapping.
*/
@PostMapping("/path")
public void writeData() {
// このメソッド内で実行される状態変更操作
}
}
解決策 (Spring Framework 4.3 以前):
@Controller
public class SafeController {
/**
* For methods without side-effects use either
* RequestMethod.GET, RequestMethod.HEAD, RequestMethod.TRACE, or RequestMethod.OPTIONS.
*/
@RequestMapping(value = "/path", method = RequestMethod.GET)
public String readData() {
// このメソッド内で状態変更操作は実行されない
return "";
}
/**
* For state-changing methods use either
* RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE, or RequestMethod.PATCH.
*/
@RequestMapping(value = "/path", method = RequestMethod.POST)
public void writeData() {
// このメソッド内で実行される状態変更操作
}
}
参考文献
Spring Security Official Documentation: Use proper HTTP verbs (CSRF protection)
OWASP: Cross-Site Request Forgery
OWASP: CSRF Prevention Cheat Sheet
CWE-352: Cross-Site Request Forgery (CSRF)
潜在的インジェクション (独自)
Bug Pattern: CUSTOM_INJECTION
特定されたメソッドはインジェクションの影響を受けやすいです。入力を検証して,適切にエスケープするべきです。
脆弱なコード:
SqlUtil.execQuery("select * from UserEntity t where id = " + parameterInput);
カスタムシグネチャを設定する方法 の詳細な手順についてはオンライン wiki を参照してください。
参考文献
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 インジェクション
Bug Pattern: SQL_INJECTION
SQL クエリーに含まれる入力値は安全に渡す必要があります。プリペアードステートメントのバインド変数を使用すると SQL インジェクションのリスクを容易に軽減できます。 プリペアードステートメントの代わりに各パラメーターを手動でエスケープすることもできます。
脆弱なコード:
createQuery("select * from User where id = '"+inputId+"'");
解決策:
import org.owasp.esapi.Encoder;
createQuery("select * from User where id = '"+Encoder.encodeForSQL(inputId)+"'");
参考文献 (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
Turbine による潜在的な SQL インジェクション
Bug Pattern: SQL_INJECTION_TURBINE
SQL クエリーに含まれる入力値は安全に渡す必要があります。プリペアードステートメントのバインド変数を使用すると SQL インジェクションのリスクを容易に軽減できます。 Turbine API は,Java コードを使用してクエリーを作成する DSL を提供します。
脆弱なコード:
List<Record> BasePeer.executeQuery( "select * from Customer where id=" + inputId );
解決策 (Criteria DSL を使用):
Criteria c = new Criteria();
c.add( CustomerPeer.ID, inputId );
List<Customer> customers = CustomerPeer.doSelect( c );
解決策 (特殊なメソッドを使用):Customer customer = CustomerPeer.retrieveByPK( new NumberKey( inputId ) );
解決策 (OWASP Encoder を使用):import org.owasp.esapi.Encoder;
BasePeer.executeQuery("select * from Customer where id = '"+Encoder.encodeForSQL(inputId)+"'");
参考文献 (Turbine)
Turbine Documentation: Criteria Howto
参考文献 (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/HQL インジェクション (Hibernate)
Bug Pattern: SQL_INJECTION_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)
CWE-564: SQL Injection: Hibernate
Hibernate Documentation: Query Criteria
Hibernate Javadoc: Query Object
HQL for pentesters: Guideline to test if the suspected code is exploitable.
参考文献 (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)
Bug Pattern: SQL_INJECTION_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)
Bug Pattern: SQL_INJECTION_JPA
SQL クエリーに含まれる入力値は安全に渡す必要があります。プリペアードステートメントのバインド変数を使用すると SQL インジェクションのリスクを容易に軽減できます。
脆弱なコード:
EntityManager pm = getEM();
TypedQuery<UserEntity> q = em.createQuery(
String.format("select * from Users where name = %s", username),
UserEntity.class);
UserEntity res = q.getSingleResult();
解決策:
TypedQuery<UserEntity> 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)
Bug Pattern: SQL_INJECTION_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 インジェクション
Bug Pattern: SQL_INJECTION_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
潜在的な Scala Slick インジェクション
Bug Pattern: SCALA_SQL_INJECTION_SLICK
SQL クエリーに含まれる入力値は安全に渡す必要があります。プリペアードステートメントのバインド変数を使用すると SQL インジェクションのリスクを容易に軽減できます。
脆弱なコード:
db.run {
sql"select * from people where name = '#$value'".as[Person]
}
解決策:
db.run {
sql"select * from people where name = $value".as[Person]
}
参考文献 (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
潜在的な Scala Anorm インジェクション
Bug Pattern: SCALA_SQL_INJECTION_ANORM
SQL クエリーに含まれる入力値は安全に渡す必要があります。プリペアードステートメントのバインド変数を使用すると SQL インジェクションのリスクを容易に軽減できます。
脆弱なコード:
val peopleParser = Macro.parser[Person]("id", "name", "age")
DB.withConnection { implicit c =>
val people: List[Person] = SQL("select * from people where name = '" + value + "'").as(peopleParser.*)
}
解決策:
val peopleParser = Macro.parser[Person]("id", "name", "age")
DB.withConnection { implicit c =>
val people: List[Person] = SQL"select * from people where name = $value".as(peopleParser.*)
}
参考文献 (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
潜在的な Android SQL インジェクション
Bug Pattern: SQL_INJECTION_ANDROID
SQL クエリーに含まれる入力値は安全に渡す必要があります。プリペアードステートメントのバインド変数を使用すると SQL インジェクションのリスクを容易に軽減できます。
脆弱なコード:
String query = "SELECT * FROM messages WHERE uid= '"+userInput+"'" ;
Cursor cursor = this.getReadableDatabase().rawQuery(query,null);
解決策:
String query = "SELECT * FROM messages WHERE uid= ?" ;
Cursor cursor = this.getReadableDatabase().rawQuery(query,new String[] {userInput});
参考文献 (Android SQLite)
InformIT.com: Practical Advice for Building Secure Android Databases in SQLite
Packtpub.com: Knowing the SQL-injection attacks and securing our Android applications from them
Android Database Support (Enterprise Android: Programming Android Database Applications for the Enterprise)
Safe example of Insert, Select, Update and Delete queries provided by Suragch
参考文献 (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 インジェクション
Bug Pattern: LDAP_INJECTION
SQL と同様に,LDAP クエリーに渡されるすべての入力は安全に渡す必要があります。残念ながら,LDAP には SQL のようなプリペアードステートメントインタフェースがありません。 そのため,LDAP インジェクションに対する一次防御は,LDAP クエリーに含める前に信頼できないデータを十分に検証することです。
リスクのあるコード:
NamingEnumeration<SearchResult> 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
スクリプトエンジン使用時の潜在的なコードインジェクション
Bug Pattern: SCRIPT_ENGINE_INJECTION
動的なコードが評価されています。コードの構築を慎重に分析するべきです。悪意のあるコードの実行は,データ漏洩やオペレーティングシステムが危険にさらされる可能性があります。
ユーザーコードの評価を意図しているなら,適切なサンドボックスを用意すべきです (参考文献を参照)。
リスクのあるコード:
public void runCustomTrigger(String script) {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
engine.eval(script); //Bad things can happen here.
}
解決策:
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: Utility to create sandbox with Rhino (block access to all classes)
CodeUtopia.net: Sandboxing Rhino in Java
Remote Code Execution .. by design: Example of malicious payload. The samples given could be used to test sandboxing rules.
CWE-94: Improper Control of Generation of Code ('Code Injection')
CWE-95: Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection')
Spring 式使用時の潜在的なコードインジェクション
Bug Pattern: SPEL_INJECTION
Spring 式は,動的な値で構築されています。フィルタされていない値が危険なコード評価になることを避けるために値の発生源を検証すべきです。
リスクのあるコード:
public void parseExpressionInterface(Person personObj,String property) {
ExpressionParser parser = new SpelExpressionParser();
//Unsafe if the input is control by the user..
Expression exp = parser.parseExpression(property+" == 'Albert'");
StandardEvaluationContext testContext = new StandardEvaluationContext(personObj);
boolean result = exp.getValue(testContext, Boolean.class);
[...]
参考文献
CWE-94: Improper Control of Generation of Code ('Code Injection')
CWE-95: Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection')
Spring Expression Language (SpEL) - Official Documentation
Minded Security: Expression Language Injection
Remote Code Execution .. by design: Example of malicious payload. The samples given could be used to test sandboxing rules.
Spring Data-Commons: (CVE-2018-1273)
Spring OAuth2: CVE-2018-1260
式言語 (EL) 使用時の潜在的なコードインジェクション
Bug Pattern: EL_INJECTION
式は動的な値で構築されています。フィルタされていない値が危険なコード評価になることを避けるために値の発生源を検証すべきです。
リスクのあるコード:
public void evaluateExpression(String expression) {
FacesContext context = FacesContext.getCurrentInstance();
ExpressionFactory expressionFactory = context.getApplication().getExpressionFactory();
ELContext elContext = context.getELContext();
ValueExpression vex = expressionFactory.createValueExpression(elContext, expression, String.class);
return (String) vex.getValue(elContext);
}
参考文献
Minded Security: Abusing EL for executing OS commands
The Java EE 6 Tutorial: Expression Language
CWE-94: Improper Control of Generation of Code ('Code Injection')
CWE-95: Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection')
Minded Security: Expression Language Injection
Dan Amodio's blog: Remote Code with Expression Language Injection
Remote Code Execution .. by design: Example of malicious payload. The samples given could be used to test sandboxing rules.
Seam ロギング呼び出しでの潜在的なコードインジェクション
Bug Pattern: SEAM_LOG_INJECTION
Seam Logging API は,ログメッセージに Bean プロパティを取り込むための式言語をサポートしています。 式言語は望まれていないコードの実行元になることもあります。
このコンテキストでは,式は動的な値で構築されています。フィルタされていない値が危険なコード評価になることを避けるために値の発生源を検証すべきです。
リスクのあるコード:
public void logUser(User user) {
log.info("Current logged in user : " + user.getUsername());
//...
}
解決策:
public void logUser(User user) {
log.info("Current logged in user : #0", user.getUsername());
//...
}
参考文献
JBSEAM-5130: Issue documenting the risk
JBoss Seam: Logging (Official documentation)
The Java EE 6 Tutorial: Expression Language
CWE-94: Improper Control of Generation of Code ('Code Injection')
CWE-95: Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection')
OGNL 式使用時の潜在的なコードインジェクション
Bug Pattern: OGNL_INJECTION
式は動的な値で構築されています。フィルタされていない値が危険なコード評価になることを避けるために値の発生源を検証すべきです。
リスクのあるコード:
public void getUserProperty(String property) {
[...]
//The first argument is the dynamic expression.
return ognlUtil.getValue("user."+property, ctx, root, String.class);
}
解決策:
一般に,OGNL 式を評価するメソッドは,ユーザー入力を受け取るべきではありません。静的構成と JSP で使用することを意図しています。
参考文献
HP Enterprise: Struts 2 OGNL Expression Injections by Alvaro Muñoz
Gotham Digital Science: An Analysis Of CVE-2017-5638
Apache Struts2: Vulnerability S2-016
Apache Struts 2 Documentation: OGNL
潜在的な HTTP レスポンス分割
Bug Pattern: HTTP_RESPONSE_SPLITTING
HTTP リクエストに予期しない CR
と LF
文字が含まれていると,サーバーは2つの異なる HTTP レスポンス (1つではなく) として解釈される出力ストリームで応答することがあります。
攻撃者は,2番目のレスポンスを制御し,クロスサイトスクリプティングやキャッシュポイズニング攻撃などの攻撃をしかけることができます。
OWASP によると,この問題はほぼすべての今の Java EE アプリケーションサーバーで修正されていますが,入力を検証することは依然として有効です。
このリスクが懸念されるときは,問題のプラットフォームでテストして,基礎となるプラットフォームが CR
または LF
文字をヘッダーに挿入できるかどうかを確認すべきです。
この弱点は SQL インジェクションなどの優先順位よりも低いと報告されています。脆弱なプラットフォームを使用しているときは,優先度の低い警告もチェックしてください。
リスクのあるコード:
String author = request.getParameter(AUTHOR_PARAMETER);
// ...
Cookie cookie = new Cookie("author", author);
response.addCookie(cookie);
参考文献
OWASP: HTTP Response Splitting
CWE-113: Improper Neutralization of CRLF Sequences in HTTP Headers ('HTTP Response Splitting')
CWE-93: Improper Neutralization of CRLF Sequences ('CRLF Injection')
ログの潜在的な CRLF インジェクション
Bug Pattern: CRLF_INJECTION_LOGS
信頼できないソースからのデータがロガーに入れられ,正しく無力化されていないと,攻撃者はログエントリーを偽造したり,悪意のあるコンテンツを含めることができます。 挿入された偽のエントリーは,統計を歪めたり,管理者を混乱させたり,悪意のある行為を委託するときに他の当事者を巻き込むために使用される可能性があります。 ログファイルが自動的に処理されていると,攻撃者はファイルの形式を破壊したり予期しない文字を注入してファイルを使用できなくすることができます。 攻撃者は,コードやその他のコマンドをログファイルに注入し,ログ処理ユーティリティの脆弱性 (コマンドインジェクションや XSS など) を利用することもできます。
リスクのあるコード:
String val = request.getParameter("user");
String metadata = request.getParameter("metadata");
[...]
if(authenticated) {
log.info("User " + val + " (" + metadata + ") was authenticated successfully");
}
else {
log.info("User " + val + " (" + metadata + ") was not authenticated");
}
悪意のあるユーザーがメタデータパラメーターに値を送信する可能性があります: "Firefox) was authenticated successfully\r\n[INFO] User bbb (Internet Explorer"
。
解決策:手動で各パラメーターをエスケープします。
log.info("User " + val.replaceAll("[\r\n]","") + " (" + userAgent.replaceAll("[\r\n]","") + ") was not authenticated");
すべてのメッセージイベントの改行を置き換えるようにロガーサービスを設定することもできます。replace
関数を使用した LogBack の設定例を示します。
<pattern>%-5level - %replace(%msg){'[\r\n]', ''}%n</pattern>
最後に,改行をスペースで書き換えるロガー実装を使用することができます。 OWASP Security Logging プロジェクトには,LogBack と Log4j の実装があります。
参考文献
CWE-117: Improper Output Neutralization for Logs
CWE-93: Improper Neutralization of CRLF Sequences ('CRLF Injection')
CWE-93: Improper Neutralization of CRLF Sequences ('CRLF Injection')
OWASP Security Logging
潜在的な構成の外部制御
Bug Pattern: EXTERNAL_CONFIG_CONTROL
システム設定の外部制御を許可するとサービスが中断されたり,アプリケーションが予期せぬ悪意のある方法で動作させられたりする可能性があります。 攻撃者は,存在しないカタログ名を指定したり,データベースの権限のない部分に接続することによってエラーを引き起こすことができます。
リスクのあるコード:
conn.setCatalog(request.getParameter("catalog"));
参考文献
CWE-15: External Control of System or Configuration Setting
不正な16進数の連結
Bug Pattern: BAD_HEXA_CONVERSION
ハッシュ署名を含むバイト配列を人間が読める文字列に変換するとき,配列がバイト単位で読み取られると変換ミスが発生する可能性があります。
次のサンプルは,計算されたハッシュ値の各バイトから先行ゼロをトリムする Integer.toHexString()
の使用方法を示しています。
MessageDigest md = MessageDigest.getInstance("SHA-256");
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" として出力されます。
このような状況では,Integer.toHexString()
メソッドを次のように String.format()
に置き換えるべきです:
stringBuilder.append( String.format( "%02X", b ) );
参考文献
CWE-704: Incorrect Type Conversion or Cast
Hazelcast 対称暗号
Bug Pattern: HAZELCAST_SYMMETRIC_ENCRYPTION
Hazelcast のネットワーク通信は,対称暗号 (おそらく DES または blowfish) を使用するように構成されています。
これらの暗号だけでは完全性や安全な認証が提供されません。非対称暗号を使用することが望ましいです。
参考文献
WASC-04: Insufficient Transport Layer Protection
Hazelcast Documentation: Encryption
CWE-326: Inadequate Encryption Strength
NullCipher は安全でない
Bug Pattern: NULL_CIPHER
NullCipher は,本番アプリケーションで意図的に使用されることはほとんどありません。 Cipher インタフェースは,与えられた平文と同一の暗号文を返すように実装されています。 テストなどのいくつかのコンテキストでは NullCipher が適切なときがあります。
脆弱なコード:
Cipher doNothingCihper = new NullCipher();
[...]
//The ciphertext produced will be identical to the plaintext.
byte[] cipherText = c.doFinal(plainText);
解決策:
NullCipher を使用しないでください。誤って使用すると重大な機密性リスクが生じる可能性があります。
参考文献
CWE-327: Use of a Broken or Risky Cryptographic Algorithm
暗号化されていないソケット
Bug Pattern: UNENCRYPTED_SOCKET
使用される通信チャネルは暗号化されていません。攻撃者がネットワークトラフィックを傍受して,トラフィックが読み取られる可能性があります。
脆弱なコード:
プレーンソケット (平文通信):
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
暗号化されていないサーバーソケット
Bug Pattern: UNENCRYPTED_SERVER_SOCKET
使用される通信チャネルは暗号化されていません。攻撃者がネットワークトラフィックを傍受して,トラフィックが読み取られる可能性があります。
脆弱なコード:
プレーンサーバーソケット (平文通信):
ServerSocket soc = new ServerSocket(1234);
解決策:
SSL サーバーソケット (安全な通信):
ServerSocket soc = SSLServerSocketFactory.getDefault().createServerSocket(1234);
SSL サーバーソケットを使用する以外に,SSLServerSocketFactory
を使用することで,中間者攻撃の対象にならないように,すべての適切な証明書検証チェックを実行する必要があります。
チェックを正しく行う方法の詳細については,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 は安全でない
Bug Pattern: DES_USAGE
DES は,今のアプリケーションでは強固な暗号とは見なされていません。現在,NIST は DES の代わりに AES ブロック暗号の使用を推奨しています。
弱いコードの例:
Cipher c = Cipher.getInstance("DES/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
DESede は安全でない
Bug Pattern: TDES_USAGE
トリプル DES (3DES または DESede としても知られている) は,今のアプリケーションでは強固な暗号とは見なされていません。 現在,NIST は 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 暗号は安全でない
Bug Pattern: RSA_NO_PADDING
ソフトウェアは RSA アルゴリズムを使用していますが,最適非対称暗号化パディング (OAEP:Optimal Asymmetric Encryption Padding) を組み込んでいないので,暗号を弱めるかもしれません。
脆弱なコード:
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
ハードコードされたパスワード
Bug Pattern: HARD_CODE_PASSWORD
パスワードをソースコード内に保持すべきではありません。ソースコードは,エンタープライズ環境で広く共有することができ,オープンソースでは確実に共有されます。 安全に管理するためには,パスワードと秘密鍵を別々の設定ファイルやキーストアに格納すべきです。 (ハードコードされた鍵は ハードコードされた鍵 パターンで別々に報告されます)
脆弱なコード:
private String SECRET_PASSWORD = "letMeIn!";
Properties props = new Properties();
props.put(Context.SECURITY_CREDENTIALS, "p@ssw0rd");
参考文献
CWE-259: Use of Hard-coded Password
ハードコードされた鍵
Bug Pattern: HARD_CODE_KEY
暗号鍵をソースコード内に保持すべきではありません。ソースコードは,エンタープライズ環境で広く共有することができ,オープンソースでは確実に共有されます。 安全に管理するためには,パスワードと秘密鍵を別々の設定ファイルやキーストアに格納すべきです。 (ハードコードされたパスワードは ハードコードされたパスワード パターンで別々に報告されます)
脆弱なコード:
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);
参考文献
CWE-321: Use of Hard-coded Cryptographic Key
安全でないハッシュの比較
Bug Pattern: UNSAFE_HASH_EQUALS
攻撃者は,比較タイミングの暴露による秘密ハッシュ値を検出できます。
関数 Arrays.equals()
または String.equals()
が呼び出されると一致するバイト数が少ないと早く終了します。
脆弱なコード:
String actualHash = ...
if(userInput.equals(actualHash)) {
...
}
解決策:
String actualHash = ...
if(MessageDigest.isEqual(userInput.getBytes(),actualHash.getBytes())) {
...
}
参考文献
CWE-203: Information Exposure Through DiscrepancyKey
入力検証がない Struts フォーム
Bug Pattern: STRUTS_FORM_VALIDATION
フォーム入力には,最低限の入力検証が必要です。予防的な検証は,さまざまなリスクに対して多重防御を提供します。
検証は,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 保護
Bug Pattern: XSS_REQUEST_WRAPPER
XSSRequestWrapper
と呼ばれる HttpServletRequestWrapper
の実装は,さまざまなブログサイトで公開されていました。
[1]
[2]
フィルタリングはいくつかの理由から弱いです:
- カバーしているのはパラメーターだけで,ヘッダーやサイドチャネル入力はカバーしていない
- 置換機能のチェーンは簡単に迂回できる (下の例を参照)
- 非常に特殊な悪いパターンのブラックリスト (良い/有効な入力のホワイトリストではなく)
迂回の例:
<scrivbscript:pt>alert(1)</scrivbscript:pt>
前述の入力は "<script>alert(1)</script>"
に変換されます。
"vbscript:"
の除去は,"<script>.*</script>"
の置換が行われた後です。
強力な保護のために,OWASP XSS Prevention Cheat Sheet で定義されている XSS 保護ルールに従って,view (template, 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 の使用
Bug Pattern: BLOWFISH_KEY_SIZE
Blowfish 暗号は,32ビットから448ビットの鍵長をサポートしています。鍵長が短いと,暗号文は総当たり攻撃 (Brute-force attack) に対して脆弱になります。 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 の使用
Bug Pattern: RSA_KEY_SIZE
NISTは,RSA アルゴリズムに 2048ビット以上 の鍵を使用することを推奨しています。
"Digital Signature Verification | RSA:1024 ≤ len(n) < 2048
| Legacy-use"
"Digital Signature Verification | RSA:len(n) ≥ 2048
| Acceptable"
- NIST: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths p.7
脆弱なコード:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(512);
解決策:
KeyPairGenerator の作成は,次のように少なくとも2048ビットの鍵長にすべきです。
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
参考文献
NIST: Latest publication on key management
NIST: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths p.7
Wikipedia: Asymmetric algorithm key lengths
CWE-326: Inadequate Encryption Strength
Keylength.com (BlueKrypt): Aggregate key length recommendations.
未検証のリダイレクト
Bug Pattern: UNVALIDATED_REDIRECT
検証されていないユーザー指定のパラメーターで指定された宛先 URL にユーザーをリダイレクトすると未検証のリダイレクトが発生します。 このような脆弱性を利用して,フィッシング攻撃を容易にすることができます。
シナリオ
1. ユーザーは,悪意のある URL にアクセスするようにだまされる: http://website.com/login?redirect=http://evil.vvebsite.com/fake/login
2. ユーザーは,信頼できるサイトのように見える偽のログインページにリダイレクトされる (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')
未検証のリダイレクト (Play Framework)
Bug Pattern: PLAY_UNVALIDATED_REDIRECT
検証されていないユーザー指定のパラメーターで指定された宛先 URL にユーザーをリダイレクトすると未検証のリダイレクトが発生します。 このような脆弱性を利用して,フィッシング攻撃を容易にすることができます。
シナリオ
1. ユーザーは,悪意のある URL にアクセスするようにだまされる: http://website.com/login?redirect=http://evil.vvebsite.com/fake/login
2. ユーザーは,信頼できるサイトのように見える偽のログインページにリダイレクトされる (http://evil.vvebsite.com/fake/login
)
3. ユーザーは自分の認証情報を入力する
4. 悪意のあるサイトはユーザーの認証情報を盗み,元の Web サイトにリダイレクトする
ほとんどのユーザーがリダイレクト後に URL をダブルチェックしないため,この攻撃は最もらしく思われます。また,認証ページへのリダイレクトもよくあります。
脆弱なコード:
def login(redirectUrl:String) = Action {
[...]
Redirect(url)
}
解決策/対策:
- ユーザーからリダイレクト先を受け入れない
- 宛先キーを受け入れ,それを使用して対象 (合法) の宛先をルックアップする
- 相対パスだけを受け入れる
- 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')
未検証のリダイレクト (Spring アプリケーション)
Bug Pattern: SPRING_UNVALIDATED_REDIRECT
検証されていないユーザー指定のパラメーターで指定された宛先 URL にユーザーをリダイレクトすると未検証のリダイレクトが発生します。 このような脆弱性を利用して,フィッシング攻撃を容易にすることができます。
シナリオ
1. ユーザーは,悪意のある URL にアクセスするようにだまされる: http://website.com/login?redirect=http://evil.vvebsite.com/fake/login
2. ユーザーは,信頼できるサイトのように見える偽のログインページにリダイレクトされる (http://evil.vvebsite.com/fake/login
)
3. ユーザーは自分の認証情報を入力する
4. 悪意のあるサイトはユーザーの認証情報を盗み,元の Web サイトにリダイレクトする
ほとんどのユーザーがリダイレクト後に URL をダブルチェックしないため,この攻撃は最もらしく思われます。また,認証ページへのリダイレクトもよくあります。
脆弱なコード:
@RequestMapping("/redirect")
public String redirect(@RequestParam("url") String url) {
[...]
return "redirect:" + url;
}
解決策/対策:
- ユーザーからリダイレクト先を受け入れない
- 宛先キーを受け入れ,それを使用して対象 (合法) の宛先をルックアップする
- 相対パスだけを受け入れる
- 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')
予期しないプロパティ漏洩
Bug Pattern: ENTITY_LEAK
永続オブジェクトは,APIによって返されるべきではありません。 UIを介してビジネスロジックが漏洩したり,データベース内の永続オブジェクトが不正に改ざんされたりする可能性があります。
脆弱なコード:
@javax.persistence.Entity
class UserEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
}
[...]
@Controller
class UserController {
@GetMapping("/user/{id}")
public UserEntity getUser(@PathVariable("id") String id) {
return userService.findById(id).get(); //Return the user entity with ALL fields.
}
}
解決策/対策:
- データ転送オブジェクトは,API への入力/応答として必要なパラメーターだけを含めて,代わりに使用する必要がある
- 機密パラメーターは,UI に転送する前に適切に削除する必要がある
- データは,適切なサニタイズチェックの後にだけデータベースに保存されるべきである
Spring MVC 解決策:
特に Spring では,次の解決策を適用して特定のフィールドを許可または禁止にできます。
@Controller
class UserController {
@InitBinder
public void initBinder(WebDataBinder binder, WebRequest request)
{
binder.setAllowedFields(["username","firstname","lastname"]);
}
}
参考文献
OWASP Top 10-2017 A3: Sensitive Data Exposure
OWASP Cheat Sheet: Mass Assignment
CWE-212: Improper Cross-boundary Removal of Sensitive Data
CWE-213: Intentional Information Exposure
一括割り当て
Bug Pattern: ENTITY_MASS_ASSIGNMENT
永続オブジェクトは,APIによって返されるべきではありません。 UIを介してビジネスロジックが漏洩したり,データベース内の永続オブジェクトが不正に改ざんされたりする可能性があります。
脆弱なコード:
@javax.persistence.Entity
class UserEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private Long role;
}
[...]
@Controller
class UserController {
@PutMapping("/user/")
@ResponseStatus(value = HttpStatus.OK)
public void update(UserEntity user) {
userService.save(user); //ALL fields from the user can be altered
}
}
一般的なガイドライン:
- データ転送オブジェクトは,API への入力/応答として必要なパラメーターだけを含めて,代わりに使用する必要がある
- 機密パラメーターは,UI に転送する前に適切に削除する必要がある
- データは,適切なサニタイズチェックの後にだけデータベースに保存されるべきである
Spring MVC 解決策:
特に Spring では,次の解決策を適用して特定のフィールドを許可または禁止にできます。
With whitelist:
@Controller
class UserController {
@InitBinder
public void initBinder(WebDataBinder binder, WebRequest request)
{
binder.setAllowedFields(["username","password"]);
}
}
With a blacklist:
@Controller
class UserController {
@InitBinder
public void initBinder(WebDataBinder binder, WebRequest request)
{
binder.setDisallowedFields(["role"]);
}
}
参考文献
OWASP Cheat Sheet: Mass Assignment
CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes
動的 JSP インクルード
Bug Pattern: JSP_INCLUDE
JSP ファイルをインクルードすることで,動的な値を入力できます。攻撃者がインクルードする JSP ページを制御する可能性があります。 その場合,攻撃者は自分が制御しているディスクにファイルを含めるように試みます。任意のファイルを含めることにより,攻撃者は任意のコードを実行できます。
脆弱なコード:
<jsp:include page="${param.secret_param}" />
解決策:
<c:if test="${param.secret_param == 'page1'}">
<jsp:include page="page1.jsp" />
</c:if>
参考文献
InfosecInstitute: File Inclusion Attacks
WASC-05: Remote File Inclusion
Spring 式の動的変数
Bug Pattern: JSP_SPRING_EVAL
Spring 式は,動的な値で構築されています。フィルタされていない値がこの危険なコード評価になることを避けるために値の発生源を検証すべきです。
脆弱なコード:
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<spring:eval expression="${param.lang}" var="lang" />
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<spring:eval expression="'${param.lang}'=='fr'" var="languageIsFrench" />
解決策:
<c:set var="lang" value="${param.lang}"/>
<c:set var="languageIsFrench" value="${param.lang == 'fr'}"/>
参考文献
CWE-94: Improper Control of Generation of Code ('Code Injection')
CWE-95: Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection')
特別な XML 文字のエスケープが無効
Bug Pattern: JSP_JSTL_OUT
潜在的な XSS を発見しました。クライアントのブラウザーで望まれていない JavaScript を実行するために使用される可能性があります。(参考文献を参照)
脆弱なコード:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:out value="${param.test_param}" escapeXml="false"/>
解決策:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:out value="${param.test_param}"/>
参考文献
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')
JSTL Javadoc: Out tag
JSP 内の潜在的な XSS
Bug Pattern: XSS_JSP_PRINT
潜在的な 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
Bug Pattern: XSS_SERVLET
潜在的な 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 ルールは類似の問題を探しますが,既存の SpotBugs のルール「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 の使用
Bug Pattern: XML_DECODER
信頼できないデータを解析するために 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
静的な初期化ベクトル (Static IV)
Bug Pattern: STATIC_IV
暗号化するメッセージごとに初期化ベクトル (IV:Initialization vector) を再生成しなければなりません。
脆弱なコード:
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 モードは安全でない
Bug Pattern: ECB_MODE
守秘義務のない Electronic Code Book (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
パディングオラクル攻撃の影響を受けやすい暗号
Bug Pattern: PADDING_ORACLE
この特定のモード (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
整合性のない暗号
Bug Pattern: CIPHER_INTEGRITY
生成された暗号文は,攻撃者によって改ざんされやすいです。これは,データが改ざんされたことを検出する方法を暗号が提供しないことを意味します。 暗号文が攻撃者によって制御される可能性があると検出されることなく変更される可能性があります。
解決策は,データに署名するためのハッシュベースのメッセージ認証コード (HMAC:Hash-based Message Authentication Code) を含む暗号を使用することです。 HMAC 関数を既存の暗号と組み合わせると,エラーが発生しやすくなります [1]。 具体的には,常に HMAC を最初に検証できることが推奨されます。データが変更されていないときに限り,データに対して暗号化関数を実行します。
次のモードは,HMAC を提供しないため脆弱です。
- CBC
- OFB
- CTR
- ECB
次のスニペットコードは,脆弱なコードの例です。
リスクのあるコード:
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 の使用
Bug Pattern: ESAPI_ENCRYPTOR
ESAPI には,暗号化コンポーネント内にちょっとした脆弱性の前歴があります。 ここでは,認証付き暗号 (Authenticated Encryption) が期待どおりに機能しているかどうかを確認する簡単な検証リストを示します。
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)。いくつかの予防措置を講ずる必要があります。
安全でない設定:
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)
Bug Pattern: ANDROID_EXTERNAL_FILE_ACCESS
アプリケーションは外部ストレージ (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)
Bug Pattern: ANDROID_BROADCAST
ブロードキャストインテントは,適切なパーミッションがあれば,どのアプリケーションでも受け取ることができます。可能であれば機密情報を送信しないようにすることをお勧めします。
リスクのあるコード:
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);
設定 (receiver)[1] Source: StackOverflow:
<manifest ...>
<!-- Permission declaration -->
<permission android:name="my.app.PERMISSION" />
<receiver
android:name="my.app.BroadcastReceiver"
android:permission="my.app.PERMISSION"> <!-- Permission enforcement -->
<intent-filter>
<action android:name="com.secure.action.UserConnected" />
</intent-filter>
</receiver>
...
</manifest>
設定 (sender)[1] Source: StackOverflow:
<manifest>
<!-- We declare we own the permission to send broadcast to the above receiver -->
<uses-permission android:name="my.app.PERMISSION"/>
<!-- With the following configuration, both the sender and the receiver apps need to be signed by the same developer certificate. -->
<permission android:name="my.app.PERMISSION" android:protectionLevel="signature"/>
</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)
Bug Pattern: ANDROID_WORLD_WRITABLE
このコンテキストで記述されたファイルは,作成モード 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
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)
Bug Pattern: ANDROID_GEOLOCATION
ジオロケーションの取得についてユーザーに確認を求めることをお勧めします。
リスクのあるコード:
webView.setWebChromeClient(new WebChromeClient() {
@Override
public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
callback.invoke(origin, true, false);
}
});
Suggested code:
ジオロケーションのサンプリングを制限し,ユーザーに確認を求めます。
webView.setWebChromeClient(new WebChromeClient() {
@Override
public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
callback.invoke(origin, true, false);
//Ask the user for confirmation
}
});
参考文献
CERT: DRD15-J. Consider privacy concerns when using Geolocation API
Wikipedia: W3C Geolocation API
W3C: Geolocation Specification
JavaScript を有効にした WebView (Android)
Bug Pattern: ANDROID_WEB_VIEW_JAVASCRIPT
WebView で JavaScript を有効にすると XSS の影響を受けやすくなります。潜在的な反映型 XSS,格納型 XSS,DOM XSS についてページレンダリングを検査すべきです。
WebView myWebView = (WebView) findViewById(R.id.webView);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
リスクのあるコード:
JavaScript を有効にすることは悪いことではありません。潜在的な XSS に対してバックエンドコードを監査する必要があることを意味します。
XSS は,クライアント側に DOM XSS を導入することもできます。
function updateDescription(newDescription) {
$("#userDescription").html("<p>"+newDescription+"</p>");
}
参考文献
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)
Bug Pattern: ANDROID_WEB_VIEW_JAVASCRIPT_INTERFACE
JavaScript インタフェースを使用すると WebView が危険な API にさらされる可能性があります。 WebView で XSS が引き起こされると,そのクラスは悪質な 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
Secure フラグがない Cookie
Bug Pattern: INSECURE_COOKIE
Secure
フラグが設定されていない新しい Cookie が作成されています。
Secure
フラグは安全でない通信 (http://
) のために Cookie が送信されないようにするためのブラウザーへの指示です。
リスクのあるコード:
Cookie cookie = new Cookie("userName",userName);
response.addCookie(cookie);
解決策 (具体的な設定):
Cookie cookie = new Cookie("userName",userName);
cookie.setSecure(true); // セキュアフラグ
cookie.setHttpOnly(true);
解決策 (Servlet 3.0 の設定):
<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="3.0">
[...]
<session-config>
<cookie-config>
<http-only>true</http-only>
<secure>true</secure>
</cookie-config>
</session-config>
</web-app>
Reference
CWE-614: Sensitive Cookie in HTTPS Session Without 'Secure' Attribute
CWE-315: Cleartext Storage of Sensitive Information in a Cookie
CWE-311: Missing Encryption of Sensitive Data
OWASP: Secure Flag
Rapid7: Missing Secure Flag From SSL Cookie
HttpOnly フラグがない Cookie
Bug Pattern: HTTPONLY_COOKIE
HttpOnly
が設定されていない新しい Cookie が作成されています。
HttpOnly
フラグは,悪意のあるスクリプトによって Cookie が読み取られないようにするためのブラウザーへの指示です。
ユーザーが XSS の対象になっていると,攻撃者はセッション ID を取得するなどの恩恵を得ます。
リスクのあるコード:
Cookie cookie = new Cookie("email",userName);
response.addCookie(cookie);
解決策 (具体的な設定):
Cookie cookie = new Cookie("email",userName);
cookie.setSecure(true);
cookie.setHttpOnly(true); //HttpOnly flag
解決策 (Servlet 3.0 の設定):
<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="3.0">
[...]
<session-config>
<cookie-config>
<http-only>true</http-only>
<secure>true</secure>
</cookie-config>
</session-config>
</web-app>
Reference
Coding Horror blog: Protecting Your Cookies: HttpOnly
OWASP: HttpOnly
Rapid7: Missing HttpOnly Flag From Cookie
オブジェクトデシリアライズの使用
Bug Pattern: OBJECT_DESERIALIZATION
悪意のある操作のきっかけを許すクラスパスにクラスが存在すると信頼できないデータのオブジェクトのデシリアライズにより,リモートコード実行を引き起こす可能性があります。
ライブラリー開発者は,潜在的な悪意のあるトリガーを提供するクラスを修正する傾向があります。 サービス拒否 [1] をもたらすことが知られているクラスはまだあります。
デシリアライゼーションは,脆弱性の歴史上気を付けなければならない操作です。 Java 仮想マシン [2] [3] に新しい脆弱性が見つかるとすぐに,Web アプリケーションが脆弱になる可能性があります。
リスクのあるコード:
public UserData deserializeObject(InputStream receivedFile) throws IOException, ClassNotFoundException {
try (ObjectInputStream in = new ObjectInputStream(receivedFile)) {
return (UserData) in.readObject();
}
}
解決策:
リモートユーザーが提供するオブジェクトのデシリアライズをしない。
参考文献
CWE-502: Deserialization of Untrusted Data
Deserialization of untrusted data
Serialization and Deserialization
A tool for generating payloads that exploit unsafe Java object deserialization
[1] Example of Denial of Service using the class java.util.HashSet
[2] OpenJDK: Deserialization issue in ObjectInputStream.readSerialData() (CVE-2015-2590)
[3] Rapid7: Sun Java Calendar Deserialization Privilege Escalation (CVE-2008-5353)
安全でない Jackson のデシリアライズ設定
Bug Pattern: JACKSON_UNSAFE_DESERIALIZATION
Jackson のデータバインドライブラリーが不正に使用され,悪意のある操作のトリガ-を可能にするクラスパスにクラスがあると 信頼できないデータのデシリアライズによりリモートコード実行を引き起こす可能性があります。
解決策:
JsonTypeInfo.Id.NAME
を介して多態性を使用するときに使用できるタイプとサブタイプを明示的に定義します。
また,ObjectMapper.enableDefaultTyping
を決して呼び出さないでください。(そして,readValue
は Object,Serializable,Comparable,または既知のデシリアライズ型を保持します)。
リスクのあるコード:
public class Example {
static class ABean {
public int id;
public Object obj;
}
static class AnotherBean {
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) // or JsonTypeInfo.Id.MINIMAL_CLASS
public Object obj;
}
public void example(String json) throws JsonMappingException {
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
mapper.readValue(json, ABean.class);
}
public void exampleTwo(String json) throws JsonMappingException {
ObjectMapper mapper = new ObjectMapper();
mapper.readValue(json, AnotherBean.class);
}
}
参考文献
Jackson Deserializer security vulnerability
Java Unmarshaller Security - Turning your data into code execution
デシリアライゼーションガジェットとして使用できるクラス
Bug Pattern: DESERIALIZATION_GADGET
デシリアライゼーションガジェットは,攻撃者がネイティブシリアライゼーションを使用してリモート API を利用するために使用できるクラスです。
このクラスは,readObject
メソッド (シリアライズ可能) を使用してデシリアライズにカスタム動作を追加するかシリアライズされたオブジェクト (InvocationHandler) から呼び出されます。
このディテクターは,主に研究者によって使用されることを意図しています。本当に問題なのは,リモート操作にデシリアライズを使用することです。 ガジェットを除去することは,悪用されるリスクを減らすための堅牢な方法です。
参考文献
CWE-502: Deserialization of Untrusted Data
Deserialization of untrusted data
Serialization and Deserialization
A tool for generating payloads that exploit unsafe Java object deserialization
[1] Example of Denial of Service using the class java.util.HashSet
[2] OpenJDK: Deserialization issue in ObjectInputStream.readSerialData() (CVE-2015-2590)
[3] Rapid7: Sun Java Calendar Deserialization Privilege Escalation (CVE-2008-5353)
Trust Boundary Violation
Bug Pattern: TRUST_BOUNDARY_VIOLATION
「信頼境界は,プログラム内部に引かれた線と考えることができます。線の片側ではデータは信頼できません。線の反対側では,データは信頼できるものと仮定されます。 検証ロジックの目的は,データが信頼境界を安全に越え,信頼できない側から信頼される側に移れるようにすることです。 信頼されているものと信頼されていないものを分ける線がプログラムで不明確なときに,Trust Boundary Violation が発生します。 信頼できるデータと信頼できないデータを同一のデータ構造で混在させることで,プログラマが誤って検証されていないデータを信頼しやすくなります。」 [1]
リスクのあるコード:
public void doSomething(HttpServletRequest req, String activateProperty) {
//..
req.getSession().setAttribute(activateProperty,"true");
}
public void loginEvent(HttpServletRequest req, String userSubmitted) {
//..
req.getSession().setAttribute("user",userSubmitted);
}
解決策:
解決策は,新しいセッション属性を設定する前に検証を追加することです。可能であれば,ダイレクトユーザー入力の使用よりも安全な場所からのデータを選びます。
参考文献
[1] CWE-501: Trust Boundary Violation
OWASP : Trust Boundary Violation
悪意のある XSLT が JSP タグに提供される可能性
Bug Pattern: JSP_XSLT
「XSLT (Extensible Stylesheet Language Transformations) は,XML 文書を他のXML文書に変換するための言語です。」[1]
スタイルシートに悪意のある振る舞いを付けることは可能です。
したがって,攻撃者がスタイルシートの内容やソースを制御できると,リモートコード実行を引き起こすことができます。[2]
リスクのあるコード:
<x:transform xml="${xmlData}" xslt="${xsltControlledByUser}" />
解決策:
解決策は,スタイルシートが安全なソースからロードされていることを確認し,パストラバーサル [3] [4] のような脆弱性が確実に起こらないようにすることです。
参考文献
[1] Wikipedia: XSLT (Extensible Stylesheet Language Transformations)
Offensive XSLT by Nicolas Gregoire
[2] From XSLT code execution to Meterpreter shells by Nicolas Gregoire
XSLT Hacking Encyclopedia by Nicolas Gregoire
Acunetix.com : The hidden dangers of XSLTProcessor - Remote XSL injection
w3.org XSL Transformations (XSLT) Version 1.0 : w3c specification
[3] WASC: Path Traversal
[4] OWASP: Path Traversal
悪意のある XSLT が提供される可能性
Bug Pattern: MALICIOUS_XSLT
「XSLT (Extensible Stylesheet Language Transformations) は,XML 文書を他のXML文書に変換するための言語です。」[1]
スタイルシートに悪意のある振る舞いを付けることは可能です。
したがって,攻撃者がスタイルシートの内容やソースを制御できると,リモートコード実行を引き起こせすことができます。[2]
リスクのあるコード:
Source xslt = new StreamSource(new FileInputStream(inputUserFile)); // 危険なソース
Transformer transformer = TransformerFactory.newInstance().newTransformer(xslt);
Source text = new StreamSource(new FileInputStream("/data_2_process.xml"));
transformer.transform(text, new StreamResult(...));
解決策:
解決策は,java.lang.Runtime
などの Java クラスへの潜在的な参照をブロックする安全な処理モードを有効にすることです。
TransformerFactory factory = TransformerFactory.newInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
Source xslt = new StreamSource(new FileInputStream(inputUserFile));
Transformer transformer = factory.newTransformer(xslt);
または,スタイルシートが安全なソースからロードされていることを確認し,パストラバーサル [3] [4] のような脆弱性が確実に起こらないようにすることです。
参考文献
[1] Wikipedia: XSLT (Extensible Stylesheet Language Transformations)
Offensive XSLT by Nicolas Gregoire
[2] From XSLT code execution to Meterpreter shells by Nicolas Gregoire
XSLT Hacking Encyclopedia by Nicolas Gregoire
Acunetix.com : The hidden dangers of XSLTProcessor - Remote XSL injection
w3.org XSL Transformations (XSLT) Version 1.0 : w3c specification
[3] WASC: Path Traversal
[4] OWASP: Path Traversal
Scala Play における潜在的な情報漏洩
Bug Pattern: SCALA_SENSITIVE_DATA_EXPOSURE
アプリケーションは,アプリケーションのさまざまな問題により意図せずに設定や内部の動作に関する情報を漏洩したり,プライバシーを侵害する可能性があります。 [1] データの正当性に基づいて異なる応答を提供するページは,情報漏洩につながります。具体的には,Web アプリケーションの設計の結果として機密と見なされるデータが漏洩したときです。[2]
機密データの例には,API キー,パスワード,製品バージョン,環境設定が含まれます (ただしこれに限定されません)。
リスクのあるコード:
def doGet(value:String) = Action {
val configElement = configuration.underlying.getString(value)
Ok("Hello "+ configElement +" !")
}
アプリケーション構成要素を応答コンテンツで送信しないでください。また,ユーザーがコードで使用する構成要素を制御できないようにすべきです。
参考文献OWASP: Top 10 2013-A6-Sensitive Data Exposure
[1] OWASP: Top 10 2007-Information Leakage and Improper Error Handling
[2] WASC-13: Information Leakage
CWE-200: Information Exposure
Scala Play Server-Side Request Forgery (SSRF)
Bug Pattern: SCALA_PLAY_SSRF
Server-Side Request Forgery (SSRF) は,Web サーバーがユーザーが指定した検証されていない宛先パラメーターへの要求を実行するときに発生します。 このような脆弱性により,攻撃者は内部サービスにアクセスしたり,Web サーバーから攻撃を開始できます。
脆弱なコード:
def doGet(value:String) = Action {
WS.url(value).get().map { response =>
Ok(response.body)
}
}
解決策/対策:
- ユーザーからリクエスト先を受け入れない
- 宛先キーを受け入れ,それを使用して対象の宛先をルックアップする
- URL のホワイトリスト (可能な場合)
- URL の先頭がホワイトリストの一部であることを検証する
参考文献
CWE-918: Server-Side Request Forgery (SSRF)
Understanding Server-Side Request Forgery
URLConnection Server-Side Request Forgery (SSRF) と File Disclosure
Bug Pattern: URLCONNECTION_SSRF_FD
Server-Side Request Forgery (SSRF) は,Web サーバーがユーザーが指定した検証されていない宛先パラメーターへの要求を実行するときに発生します。 このような脆弱性により,攻撃者は内部サービスにアクセスしたり,Web サーバーから攻撃を開始できます。
URLConnection は,file:// プロトコルまたは他のプロトコルと共に使用して,ローカルファイルシステムやその他のサービスにアクセスできます。
脆弱なコード:
new URL(String url).openConnection()
new URL(String url).openStream()
new URL(String url).getContent()
解決策/対策:
- ユーザーから URL 宛先を受け入れない
- 宛先キーを受け入れ,それを使用して対象 (合法) の宛先をルックアップする
- URL のホワイトリスト (可能な場合)
- URL の先頭がホワイトリストの一部であることを検証する
参考文献
CWE-918: Server-Side Request Forgery (SSRF)
Understanding Server-Side Request Forgery
CWE-73: External Control of File Name or Path
Abusing jar:// downloads
Scala Twirl テンプレートエンジンの潜在的な XSS
Bug Pattern: SCALA_XSS_TWIRL
潜在的な XSS を発見しました。クライアントのブラウザーで望まれていない JavaScript を実行するために使用される可能性があります。(参考文献を参照)
脆弱なコード:
@(value: Html)
@value
解決策:
@(value: String)
@value
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
Scala MVC API エンジンの潜在的な XSS
Bug Pattern: SCALA_XSS_MVC_API
潜在的な XSS を発見しました。クライアントのブラウザーで望まれていない JavaScript を実行するために使用される可能性があります。(参考文献を参照)
脆弱なコード:
def doGet(value:String) = Action {
Ok("Hello " + value + " !").as("text/html")
}
解決策:
def doGet(value:String) = Action {
Ok("Hello " + Encode.forHtml(value) + " !")
}
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
Velocity の潜在的なテンプレートインジェクション
Bug Pattern: TEMPLATE_INJECTION_VELOCITY
Velocity テンプレートエンジンは強力です。条件文,ループ,外部呼び出しなどのロジックを追加することができます。 テンプレート操作をサンドボックスにすることは設計されていません。テンプレートを制御する悪意のあるユーザーは,サーバー側で悪意のあるコードを実行する可能性があります。 Velocity テンプレートはスクリプトとしてみなすべきです。
脆弱なコード:
[...]
Velocity.evaluate(context, swOut, "test", userInput);
解決策:
エンドユーザーが Velocity を使用してテンプレートを操作できないようにします。
テンプレート編集をユーザーに公開する必要があるときは,Handlebars や Mustache などのロジックレステンプレートエンジンを使用することをお勧めします。(参考文献を参照)
参考文献
PortSwigger: Server-Side Template Injection
Handlebars.java
Freemarker の潜在的なテンプレートインジェクション
Bug Pattern: TEMPLATE_INJECTION_FREEMARKER
Freemarker テンプレートエンジンは強力です。条件文,ループ,外部呼び出しなどのロジックを追加することができます。 テンプレート操作をサンドボックスにすることは設計されていません。テンプレートを制御する悪意のあるユーザーは,サーバー側で悪意のあるコードを実行する可能性があります。 Freemarker テンプレートはスクリプトとして見なすべきです。
脆弱なコード:
Template template = cfg.getTemplate(inputTemplate);
[...]
template.process(data, swOut);
解決策:
エンドユーザーが Freemarker を使用してテンプレートを操作できないようにします。
テンプレート編集をユーザーに公開する必要があるときは,Handlebars や Mustache などのロジックレステンプレートエンジンを使用することをお勧めします。(参考文献を参照)
参考文献
PortSwigger: Server-Side Template Injection
Handlebars.java
Pebble の潜在的なテンプレートインジェクション
Bug Pattern: TEMPLATE_INJECTION_PEBBLE
Pebble テンプレートエンジンは強力です。条件文,ループ,外部呼び出しなどのロジックを追加することができます。 テンプレート操作をサンドボックスにすることは設計されていません。テンプレートを制御する悪意のあるユーザーは,サーバー側で悪意のあるコードを実行する可能性があります。 Pebble テンプレートはスクリプトとして見なすべきです。
脆弱なコード:
PebbleTemplate compiledTemplate = engine.getLiteralTemplate(inputFile);
[...]
compiledTemplate.evaluate(writer, context);
解決策:
エンドユーザーが Pebble を使用してテンプレートを操作できないようにします。
テンプレート編集をユーザーに公開する必要があるときは,Handlebars や Mustache などのロジックレステンプレートエンジンを使用することをお勧めします。(参考文献を参照)
参考文献
Server Side Template Injection ? on the example of Pebble by Micha? Bentkowski
PortSwigger: Server-Side Template Injection
Handlebars.java
過剰に許可された CORS ポリシー
Bug Pattern: PERMISSIVE_CORS
HTML5 以前の Web ブラウザーでは,同一生成元ポリシーが強制されます。このポリシーは,JavaScript が Web ページのコンテンツにアクセスするために,JavaScript と Web ページの両方が同じドメインを由来としていなければなりません。 同一生成元ポリシーが適用されないと,悪意のある Web サイトはクライアントの認証情報を使用して他の Web サイトから機密情報をロードする JavaScript を仕込むことができ,選び取った情報を攻撃者に返します。 Access-Control-Allow-Origin という新しい HTTP ヘッダーが定義されていると,HTML5 では,JavaScript はドメイン間でデータにアクセスすることが可能です。 生成元間のリクエストを使用してドメインにアクセスすることを許可する他のドメインを,Web サーバーはこのヘッダーを使用して定義します。 しかし,このヘッダーを定義する場合には,注意が必要です。過剰に許可された CORS ポリシーは,悪意のあるアプリケーションが不正な方法で攻撃対象のアプリケーションとやりとりをして,偽装,データの盗み出し,リレー,およびその他の攻撃が実行される恐れがあります。
脆弱なコード:
response.addHeader("Access-Control-Allow-Origin", "*");
解決策:
Access Control-Allow-Origin ヘッダーの値としてワイルドカード (*) を使用しないでください。アプリケーションのデータが,任意のドメインで実行される JavaScript にアクセスできることになります。
参考文献
W3C Cross-Origin Resource Sharing
Enable Cross-Origin Resource Sharing
匿名 LDAP バインド
Bug Pattern: LDAP_ANONYMOUS
適切なアクセス制御がなく,ユーザーの制御下にある値を含む LDAP ステートメントを実行すると,攻撃者は不適切な設定となっている LDAP コンテキストを悪用できます。 コンテキストに対するすべての LDAP クエリーは,認証とアクセス制御なしで実行されます。 攻撃者は,これらのクエリーのいずれかを予期せぬ方法で操作して,ディレクトリーのアクセス制御メカニズムにより保護されているレコードにアクセスすることができます。
脆弱なコード:
...
env.put(Context.SECURITY_AUTHENTICATION, "none");
DirContext ctx = new InitialDirContext(env);
...
解決策:
LDAP に対する他の認証モードを検討し,適切なアクセス制御メカニズムを確保してください。
参考文献
Ldap Authentication Mechanisms
LDAP Entry Poisoning
Bug Pattern: LDAP_ENTRY_POISONING
JNDI API は,LDAP ディレクトリー内のシリアライズオブジェクトのバインディングをサポートします。 特定の属性が提示されていると,オブジェクトのデシリアライズは,ディレクトリーを照会するアプリケーションで行われます (詳細は Black Hat USA 2016ホワイトペーパーを参照)。 オブジェクトのデシリアライズは,リモートコード実行につながる可能性のある危険な操作であることを考慮すべきです。
LDAP ベースクエリーにエントリポイントを持っていると,攻撃者が既存の LDAP エントリに属性を追加するか,悪意のある LDAP サーバーを使用するようにアプリケーションを構成することにより,この脆弱性が悪用される可能性があります。
脆弱なコード:
DirContext ctx = new InitialDirContext();
//[...]
ctx.search(query, filter,
new SearchControls(scope, countLimit, timeLimit, attributes,
true, //Enable object deserialization if bound in directory
deref));
解決策:
DirContext ctx = new InitialDirContext();
//[...]
ctx.search(query, filter,
new SearchControls(scope, countLimit, timeLimit, attributes,
false, //Disable
deref));
参考文献
Black Hat USA 2016: A Journey From JNDI/LDAP Manipulation to Remote Code Execution Dream Land
(slides & video) by Alvaro Muñoz and Oleksandr Mirosh
HP Enterprise: Introducing JNDI Injection and LDAP Entry Poisoning by Alvaro Muñoz
TrendMicro: How The Pawn Storm Zero-Day Evaded Java's Click-to-Play Protection by Jack Tang
永続的 Cookie の使用
Bug Pattern: COOKIE_PERSISTENT
永続的 Cookie に機密データーを長期間保管すると,機密性が損なわれたり,アカウントが悪用される可能性があります。
説明:
永続的 Cookie では有効期限がずっと先に設定されることが多いため,永続的 Cookie に個人情報が保管されていると,攻撃者が情報を盗み出すことのできる時間が長くなります。
永続的 Cookie は通常,クライアント上のテキストファイルに保存され,被害者のマシンにアクセスできる攻撃者はこの情報を盗むことができます。
永続的 Cookie は,サイトとやり取りするときのユーザープロファイルとして使用されます。
この追跡データに対して実行される操作によっては,ユーザーの個人情報を盗み出すのに永続的 Cookie が使用される可能性があります。
脆弱なコード: 次のコードは,Cookie が1年間で期限切れになるよう設定します。
[...]
Cookie cookie = new Cookie("email", email);
cookie.setMaxAge(60*60*24*365);
[...]
解決策:
- 永続的 Cookie は,必要なときにだけ使用し,最大有効期間を制限する
- 重要なデータに永続的 Cookie を使用しない
参考文献
Class Cookie setMaxAge
documentation
CWE-539: Information Exposure Through Persistent Cookies
URL を書き換えるメソッド
Bug Pattern: URL_REWRITING
このメソッドの実装には,セッション ID を URL にエンコードする必要があるかどうかを判断するロジックが含まれています。
URL の書き換えには,セキュリティ上の重大なリスクがあります。セッション ID が URL に表示されるので,第三者が容易に見ることができます。
URL のセッション ID は,さまざまな方法で公開できます。たとえば,次のようになります。
- ログファイル
- ブラウザーの履歴
- 電子メールや投稿にコピーアンドペーストすることにより
- HTTP のリファラー
脆弱なコード:
out.println("Click <a href=" +
res.encodeURL(HttpUtils.getRequestURL(req).toString()) +
">here</a>");
解決策:
これらのメソッドを使用しないでください。URL 文字列またはフォームパラメーターをエンコードするときは,URL を書き換えるメソッドと URLEncoder クラスを混同しないでください。
参考文献
OWASP Top 10 2010-A3-Broken Authentication and Session Management
安全でない SMTP SSL 接続
Bug Pattern: INSECURE_SMTP_SSL
SSL 接続を確立すると,サーバー ID の確認は無効になります。SSL 接続を有効にする電子メールライブラリーによっては,デフォルトでサーバー証明書を検証しません。 これは,すべての証明書を信頼することと同じです。サーバーに接続しようとすると,このアプリケーションは "victim.com" に対して発行された証明書をすぐに受け入れます。 アプリケーションは,victim サーバーへの不正な SSL接続によって,ユーザー機密情報を漏洩させる可能性があります。
脆弱なコード:
...
Email email = new SimpleEmail();
email.setHostName("smtp.servermail.com");
email.setSmtpPort(465);
email.setAuthenticator(new DefaultAuthenticator(username, password));
email.setSSLOnConnect(true);
email.setFrom("user@gmail.com");
email.setSubject("TestMail");
email.setMsg("This is a test mail ... :-)");
email.addTo("foo@bar.com");
email.send();
...
解決策:
次のチェックを追加してサーバ証明書を確認してください:
email.setSSLCheckServerIdentity(true);
参考文献
CWE-297: Improper Validation of Certificate with Host Mismatch
AWS Query インジェクション
Bug Pattern: AWS_QUERY_INJECTION
ユーザー入力を含む SimpleDB クエリーを構築すると,攻撃者が権限のないレコードを閲覧できます。
次の例では,ユーザーが productCategory を指定できるようにする SimpleDB SELECT クエリーを動的に構築して実行します。
攻撃者は,クエリーを変更し,customerID に必要な認証を回避し,任意の顧客に一致するレコードを表示できます。
脆弱なコード:
...
String customerID = getAuthenticatedCustomerID(customerName, customerCredentials);
String productCategory = request.getParameter("productCategory");
...
AmazonSimpleDBClient sdbc = new AmazonSimpleDBClient(appAWSCredentials);
String query = "select * from invoices where productCategory = '"
+ productCategory + "' and customerID = '"
+ customerID + "' order by '"
+ sortColumn + "' asc";
SelectResult sdbResult = sdbc.select(new SelectRequest(query));
解決策:
この問題は SQL インジェクションに似ています。SimpleDB クエリーを使用する前にユーザー入力をエスケープします。
参考文献
CWE-943: Improper Neutralization of Special Elements in Data Query Logic
JavaBeans プロパティインジェクション
Bug Pattern: BEAN_PROPERTY_INJECTION
攻撃者は,システムの整合性を損なう任意の Bean プロパティを設定できます。Bean 入力機能は,Bean プロパティまたはネストされたプロパティを設定できます。
攻撃者がこの機能を利用して,システムプロパティを上書きして任意のコードを実行できるようにする class.classLoader
のような特殊な Bean プロパティにアクセスする可能性があります。
脆弱なコード:
MyBean bean = ...;
HashMap map = new HashMap();
Enumeration names = request.getParameterNames();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
map.put(name, request.getParameterValues(name));
}
BeanUtils.populate(bean, map);
解決策:
ユーザーが制御する値を使用して Bean プロパティ名を設定しないでください。
参考文献
CWE-15: External Control of System or Configuration Setting
Struts File Disclosure
Bug Pattern: STRUTS_FILE_DISCLOSURE
ユーザー入力を使用してサーバーサイドリダイレクトパスを作成すると,攻撃者にアプリケーションのバイナリ (アプリケーションクラスや jar ファイルを含む) をダウンロードされたり保護されているディレクトリ内の任意のファイルを表示されたりする可能性があります。
攻撃者は,重要なファイルの場所と一致するリクエストパラメーターを偽造できます。
たとえば,"http://example.com/?returnURL=WEB-INF/applicationContext.xml"
を要求すると,アプリケーションの applicationContext.xml
ファイルが表示されます。
攻撃者は,他の構成ファイル,クラスファイル,jar ファイルで参照されている applicationContext.xml
を見つけてダウンロードし,機密情報を取得して他の種類の攻撃を開始できます。
脆弱なコード:
...
String returnURL = request.getParameter("returnURL");
Return new ActionForward(returnURL);
...
解決策:
ユーザーが制御する入力を使用してサーバーサイドリダイレクトを構成しないでください。
参考文献
CWE-552: Files or Directories Accessible to External Parties
Spring File Disclosure
Bug Pattern: SPRING_FILE_DISCLOSURE
ユーザー入力を使用してサーバーサイドリダイレクトパスを作成すると,攻撃者にアプリケーションのバイナリ (アプリケーションクラスや jar ファイルを含む) をダウンロードされたり保護されているディレクトリ内の任意のファイルを表示されたりする可能性があります。
攻撃者は,重要なファイルの場所と一致するリクエストパラメーターを偽造できます。
たとえば,"http://example.com/?jspFile=../applicationContext.xml%3F"
を要求すると,アプリケーションの applicationContext.xml
ファイルが表示されます。
攻撃者は,他の構成ファイル,クラスファイル,jar ファイルで参照されている applicationContext.xml
を見つけてダウンロードし,機密情報を取得して他の種類の攻撃を開始できます。
脆弱なコード:
...
String returnURL = request.getParameter("returnURL");
return new ModelAndView(returnURL);
...
解決策:
ユーザーが制御する入力を使用してサーバーサイドリダイレクトを構成しないでください。
参考文献
CWE-552: Files or Directories Accessible to External Parties
RequestDispatcher File Disclosure
Bug Pattern: REQUESTDISPATCHER_FILE_DISCLOSURE
ユーザー入力を使用してサーバーサイドリダイレクトパスを作成すると,攻撃者にアプリケーションのバイナリ (アプリケーションクラスや jar ファイルを含む) をダウンロードされたり保護されているディレクトリ内の任意のファイルを表示されたりする可能性があります。
攻撃者は,重要なファイルの場所と一致するリクエストパラメーターを偽造できます。
たとえば,"http://example.com/?jspFile=../applicationContext.xml%3F"
を要求すると,アプリケーションの applicationContext.xml
ファイルが表示されます。
攻撃者は,他の構成ファイル,クラスファイル,jar ファイルで参照されている applicationContext.xml
を見つけてダウンロードし,機密情報を取得して他の種類の攻撃を開始できます。
脆弱なコード:
...
String jspFile = request.getParameter("jspFile");
request.getRequestDispatcher("/WEB-INF/jsps/" + jspFile + ".jsp").include(request, response);
...
解決策:
ユーザーが制御する入力を使用してサーバーサイドリダイレクトを構成しないでください。
参考文献
CWE-552: Files or Directories Accessible to External Parties
書式文字列操作
Bug Pattern: FORMAT_STRING_MANIPULATION
ユーザー入力で書式パラメーターが制御できるようになっていると,攻撃者が例外を投げたり情報を漏洩させたりすることができます。
攻撃者は,書式文字列の引数を変更して,例外がスローされるようにすることができます。この例外がキャッチされなかった場合,アプリケーションがクラッシュする可能性があります。
あるいは,未使用の引数内で機密情報が使用されると,攻撃者はこの情報を暴露するために書式文字列を変更できます。
次のコード例では,残高を示す小数点をユーザーが指定できます。実際には,例外がスローされる原因となるものを指定することができ,アプリケーションの障害を引き起こす可能性があります。
この例ではさらに重要なことに,攻撃者がユーザー入力 "2f %3$s %4$.2"
を指定できると,書式文字列は "The customer: %s %s has the balance %4$.2f %3$s %4$.2"
となります。
これにより,結果文字列に機密の accountNo
が含まれることになります。
脆弱なコード:
Formatter formatter = new Formatter(Locale.US);
String format = "The customer: %s %s has the balance %4$." + userInput + "f";
formatter.format(format, firstName, lastName, accountNo, balance);
解決策:
書式文字列引数にユーザーが制御する値を使用しないでください。
参考文献
CWE-134: Use of Externally-Controlled Format String
HTTP Parameter Pollution
Bug Pattern: HTTP_PARAMETER_POLLUTION
未検証のユーザー入力を URL に連結すると,攻撃者にリクエストパラメーターの値の上書きを許します。
攻撃者が,既存のパラメーターの値を上書きしたり,新しいパラメーターを挿入したり,直接到達できない変数を利用したりすることができます。
HTTP Parameter Pollution (HPP) 攻撃は,エンコードしたクエリー文字列区切り文字を他の既存のパラメーターに挿入することで成り立ちます。
Web アプリケーションがユーザー入力を適切にエスケープしていないと,悪意のあるユーザーがアプリケーションのロジックを侵害して,クライアント側またはサーバー側の攻撃を実行する可能性があります。
次の例では,プログラマは,攻撃者が en&user_id=1
のような lang
を指定できる可能性を考慮していないため,攻撃者が思いのままに user_id
を変更できます。
脆弱なコード:
String lang = request.getParameter("lang");
GetMethod get = new GetMethod("http://www.host.com");
get.setQueryString("lang=" + lang + "&user_id=" + user_id);
get.execute();
解決策:
HTTP パラメーターで使用する前にユーザー入力をエスケープします。
参考文献
CAPEC-460: HTTP Parameter Pollution (HPP)
エラーメッセージによる情報漏洩
Bug Pattern: INFORMATION_EXPOSURE_THROUGH_AN_ERROR_MESSAGE
機密情報は,それ自体で貴重な情報(パスワードなど)である場合もあれば他のより致命的な攻撃を仕かけるのに役立つ場合もあります。 攻撃が失敗した場合,攻撃者はサーバーから提供されたエラー情報を使用して,より焦点を絞った別の攻撃を開始できます。 たとえば,パストラバーサルの弱点 (CWE-22) を悪用しようとするとインストールされているアプリケーションの完全パス名が得られる可能性があります。 次に,これを使用して,適切な数の「..」シーケンスを選択し,ターゲットファイルに移動します。 SQLインジェクション (CWE-89) を使用した攻撃は,最初は成功しないかもしれませんが,エラーメッセージによって不正なクエリが明らかになり,クエリロジック,さらにはクエリ内で使用されるパスワードやその他の機密情報が明らかになる可能性があります。
脆弱なコード:
try {
out = httpResponse.getOutputStream()
} catch (Exception e) {
e.printStackTrace(out);
}
参考文献
CWE-209: Information Exposure Through an Error Message
CWE-211: Information Exposure Through Externally-Generated Error Message
SMTP ヘッダーインジェクション
Bug Pattern: SMTP_HEADER_INJECTION
Simple Mail Transfer Protocol (SMTP) は,電子メール配信に使用されるテキストベースのプロトコルです。
HTTP と同様に,ヘッダーは改行で区切られます。
ユーザ入力がヘッダー行にある場合,アプリケーションは改行文字 (CR
/ LF
) を削除または置換すべきです。
Apache Common Email や Simple Java Mail などの安全なラッパーを使用して,ヘッダーインジェクションにつながる特殊文字をフィルタすべきです。
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress("noreply@your-organisation.com"));
message.setRecipients(Message.RecipientType.TO, new InternetAddress[] {new InternetAddress("target@gmail.com")});
message.setSubject(usernameDisplay + " has sent you notification"); //Injectable API
message.setText("Visit your ACME Corp profile for more info.");
Transport.send(message);
解決策Use Apache Common Email or Simple Java Mail.
参考文献
OWASP SMTP Injection
CWE-93: Improper Neutralization of CRLF Sequences ('CRLF Injection')
Commons Email: User Guide
Simple Java Mail Website
StackExchange InfoSec: What threats come from CRLF in email generation?
有効なApache XML RPC サーバーまたはクライアントの拡張機能
Bug Pattern: RPC_ENABLED_EXTENSIONS
Apache XML RPCサーバーまたはクライアントで拡張機能を有効にすると,デシリアライズの脆弱性が発生する可能性があります。
これにより,攻撃者が任意のコードを実行することができるようになります。
org.apache.xmlrpc.client.XmlRpcClientConfigImpl
または org.apache.xmlrpc.XmlRpcConfigImpl
の setEnabledForExtensions
メソッドを使用しないことをお勧めします。
デフォルトでは,拡張機能はクライアントとサーバーの両方で無効になっています。
参考文献
0ang3el's Blog: Beware of WS-XMLRPC library in your Java App
CVE-2016-5003 vulnerability reference
HTMLエスケープを無効にすると,アプリケーションが XSS の危険にさらされる
Bug Pattern: WICKET_XSS1
HTMLエスケープを無効にすると,アプリケーションがクロスサイトスクリプティング (XSS) の危険にさらされます。
脆弱なコード:
add(new Label("someLabel").setEscapeModelStrings(false));
参考文献
Wicket models and forms - Reference Documentation
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')
SAML で XML コメントを無視すると,認証バイパスが発生する可能性がある
Bug Pattern: SAML_IGNORE_COMMENTS
Security Assertion Markup Language (SAML) は,XML を使用したシングルサインオンプロトコルです。
SAMLResponse メッセージには,認証されたユーザーを記述するステートメントが含まています
ユーザーが XML コメント (<!-- -->
) を配置すると,パーサーがリテラル値を抽出する方法で問題が発生する可能性があります。
たとえば,次の XML セクションを見てみましょう:
<saml:Subject><saml:NameID>admin@domain.com<!---->.evil.com</saml:NameID></saml:Subject>
ユーザー ID は,"admin@domain.com<!---->.evil.com"
ですが,実際にはテキストノード "admin@domain.com"
,コメント ""
,テキストノード ".evil.com"
です。
NameID を抽出すると,サービスプロバイダーの実装は,最初のノードまたは最後のノードとなることがあります。
脆弱なコード:
@Bean
ParserPool parserPool1() {
BasicParserPool pool = new BasicParserPool();
pool.setIgnoreComments(false);
return pool;
}
解決策:
@Bean
ParserPool parserPool1() {
BasicParserPool pool = new BasicParserPool();
pool.setIgnoreComments(true);
return pool;
}
参考文献
Duo Finds SAML Vulnerabilities Affecting Multiple Implementations
Spring Security SAML and this week's SAML Vulnerability
過剰に許可されたファイルパーミッション
Bug Pattern: OVERLY_PERMISSIVE_FILE_PERMISSION
一般に,すべてのユーザーに read+write+exec などの過剰に許可されたファイルパーミッションを設定することは悪い習慣です。 影響を受けるファイルが構成,バイナリ,スクリプト,または機密データである場合,権限昇格または情報漏洩につながる可能性があります。
アプリケーションと同じホストで実行されている別のサービスが危険にさらされる可能性があります。 通常,サービスは別のユーザーで実行されます。 侵害されたサービスアカウントは,構成の読み取り,スクリプトへの実行命令の追加,データファイルの変更に使用される可能性があります。 他のサービスやローカルユーザーからのダメージを制限するには,アプリケーションファイルのパーミッションに制限するべきです。
脆弱なコード 1 (シンボリック表記):
Files.setPosixFilePermissions(configPath, PosixFilePermissions.fromString("rw-rw-rw-"));
解決策 1 (シンボリック表記):
Files.setPosixFilePermissions(configPath, PosixFilePermissions.fromString("rw-rw----"));
脆弱なコード 2 (オブジェクト指向実装):
Set<PosixFilePermission> perms = new HashSet<>();
perms.add(PosixFilePermission.OWNER_READ);
perms.add(PosixFilePermission.OWNER_WRITE);
perms.add(PosixFilePermission.OWNER_EXECUTE);
perms.add(PosixFilePermission.GROUP_READ);
perms.add(PosixFilePermission.GROUP_WRITE);
perms.add(PosixFilePermission.GROUP_EXECUTE);
perms.add(PosixFilePermission.OTHERS_READ);
perms.add(PosixFilePermission.OTHERS_WRITE);
perms.add(PosixFilePermission.OTHERS_EXECUTE);
解決策 2 (オブジェクト指向実装):
Set<PosixFilePermission> perms = new HashSet<>();
perms.add(PosixFilePermission.OWNER_READ);
perms.add(PosixFilePermission.OWNER_WRITE);
perms.add(PosixFilePermission.OWNER_EXECUTE);
perms.add(PosixFilePermission.GROUP_READ);
perms.add(PosixFilePermission.GROUP_WRITE);
perms.add(PosixFilePermission.GROUP_EXECUTE);
参考文献
CWE-732: Incorrect Permission Assignment for Critical Resource
A guide to Linux Privilege Escalation
File system permissions