Bugs Patterns

The complete list of descriptions given when FindBugs identify potential weaknesses.

Table of Contents

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 (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: 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

Bug Pattern: SERVLET_CONTENT_TYPE

HTTP ヘッダー Content-Type は,クライアントによって操作可能です。したがって,その値をセキュリティ上重要な決定では使用しないでください。


参考文献
CWE-807: Untrusted Inputs in a Security Decision

Bug Pattern: SERVLET_SERVER_NAME

Host ヘッダーは,クライアントによって操作可能です。したがって,その値をセキュリティ上重要な決定では使用しないでください。 ServletRequest.getServerName()HttpServletRequest.getHeader("Host") は,どちらも Host ヘッダーを抽出するという同じ動作をします。

GET /testpage HTTP/1.1
Host: www.example.com
[...]

アプリケーションにサービスを提供するウェブコンテナは,デフォルトでは,アプリケーションにリクエストをリダイレクトすることがあります。 これにより,悪意のあるユーザーが Host ヘッダーで任意の値を配置できるようになります。 リクエストに関して行うセキュリティ上の決定において,この値を信頼しないことをお勧めします。


参考文献
CWE-807: Untrusted Inputs in a Security Decision

Bug Pattern: SERVLET_SESSION_ID

メソッド HttpServletRequest.getRequestedSessionId() は, 通常,クッキー JSESSIONID の値を返します。この値は通常,セッション管理ロジックと正常でない開発者コードだけがアクセスします。

クライアントに渡される値は一般的に英数字の値です (例えば JSESSIONID=jp6q31lq2myn)。しかし,この値はクライアントによって改ざんできます。 次の HTTP リクエストは変更の可能性を示しています。

GET /somePage HTTP/1.1
Host: yourwebsite.com
User-Agent: Mozilla/5.0
Cookie: JSESSIONID=Any value of the user's choice!!??'''">

そのため,JSESSIONID は,その値が既存のセッション ID と一致するかどうかを確認するためだけに使用されるべきです。 そうでない場合,そのユーザーは認証されていないユーザーであると考えるべきです。加えて,セッション ID の値をログに記録してはいけません。 その場合,ログファイルには有効なアクティブセッション ID を含むことができ,ID がログに記録されかつアクティブなままであるすべてのセッションを内部者がハイジャックすることを許してしまいます。


参考文献
OWASP: Session Management Cheat Sheet
CWE-20: Improper Input Validation

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

Bug Pattern: SERVLET_HEADER

リクエストヘッダーはリクエストしているユーザーによって容易に改ざんできます。 一般的には,ブラウザーから攻撃者による変更がないリクエストが来ることを仮定すべきではありません。 このように,リクエストに関して行うあらゆるセキュリティ上の決定において,その値を信頼しないでください。


参考文献
CWE-807: Untrusted Inputs in a Security Decision

Bug Pattern: SERVLET_HEADER_REFERER

動作:

  • リクエストが悪意のあるユーザーから来ているなら,任意の値をこのヘッダーに割り当てられます。
  • リクエストが安全 (https) である別のオリジンから開始されたときは,"Referer" は存在しません。

推奨:

  • このヘッダーの値に基づいてアクセス制御を行うべきではありません。
  • CSRF 保護は,この値にだけ基づいて行われるべきではありません (オプションなので)。


参考文献
CWE-807: Untrusted Inputs in a Security Decision

Bug Pattern: SERVLET_HEADER_USER_AGENT

ヘッダー "User-Agent" は,クライアントによって容易に偽装できます。User-Agent に基づいて (クローラー UA に対して) 異なった動作をすることは推奨できません。


参考文献
CWE-807: Untrusted Inputs in a Security Decision

Bug Pattern: COOKIE_USAGE

カスタムクッキーに格納する情報は,機密やセッションに関連してはいけません。ほとんどの場合,機密データはセッションだけに格納して,ユーザーのセッションクッキーによってだけ参照されるべきです。 HttpSession (HttpServletRequest.getSession()) を参照してください。

カスタムクッキーは,特定のセッションから独立した,より長く存続する必要がある情報のために使用できます。


参考文献
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')

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 // Weak point
    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 // Fix
    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')

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')

Bug Pattern: WEAK_FILENAMEUTILS

FilenameUtils のいくつかのメソッドは NULL バイト (0x00) をフィルターしません。

NULL バイトがファイル名に挿入され,そのファイル名が OS に渡されると取得されるファイルは NULL バイトより前に指定されたファイル名になります。 OS レベルであるので,たとえ Java 自体が NULLl バイトを気にしたり特別扱いをしなくても,すべての文字列が NULL バイトで終了するためです。 この OS の動作は,ファイル名の検証を「ファイル名の末尾 (たとえば,末尾が ".log" であるか) を調べ,アクセスしても安全なファイルであるかを確認」といった具合にしていると回避されてしまうことがあります。

これを修正するためには,次の2つのことが推奨されています:

NULL バイトインジェクションの影響を受けない最新版の Java を使用していることがわかっているなら,このルールを無効にできます。


参考文献
WASC-28: Null Byte Injection
CWE-158: Improper Neutralization of Null Byte or NUL Character

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

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

Bug Pattern: JAXWS_ENDPOINT

このメソッドは,SOAP Web サービス (JSR224) の一部です。

この Web サービスの安全性を分析する必要があります。たとえば:

  • 認証を強制したときはテストすべきです。
  • アクセス制御を強制したときはテストすべきです。
  • 潜在的な脆弱性のために入力を追跡すべきです。
  • 通信は理想的には SSL の上で行うべきです。


参考文献
OWASP: Web Service Security Cheat Sheet
CWE-20: Improper Input Validation

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

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

Bug Pattern: WICKET_ENDPOINT

このクラスは,Wicket の WebPage を表します。入力はコンストラクターに渡された PageParameters インスタンスから自動的に読み出されます。 現在のページは, ビュー [/package/WebPageName].html にマッピングされます。

このアプリケーションの各 Wicket ページは,このように自動的にマッピングされるすべての入力を使用される前に適切に検証されているか調査すべきです。


参考文献
Apache Wicket Home Page
CWE-20: Improper Input Validation

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: Transitions: Recommendation for 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: Transitions: Recommendation for 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

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: Transitions: Recommendation for 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: Transitions: Recommendation for 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

Bug Pattern: DEFAULT_HTTP_CLIENT

脆弱なコード:

    HttpClient client = new DefaultHttpClient();

解決策:
推奨構成の1つを使用して,https.protocols JVM オプションを TLSv1.2 を含むように設定して,実装を改良します:

  • 代わりに SystemDefaultHttpClient を使用します。
  • サンプルコード:

        HttpClient client = new SystemDefaultHttpClient();
    

  • SSLSocketFactory に基づいて HttpClient を作成します - getSystemSocketFactory() で SSLSocketFactory のインスタンスを取得して,HttpClient の作成に使用します。
  • SSLConnectionSocketFactory に基づいて HttpClient を作成する - getSystemSocketFactory() でインスタンスを取得して,HttpClient の作成に使用します。
  • HttpClientBuilder を使用します - build() を呼び出す前に useSystemProperties() を呼び出します。
  • サンプルコード:

        HttpClient client = HttpClientBuilder.create().useSystemProperties().build();
    

  • HttpClients - createSystem() を呼び出してインスタンスを作成します。
  • サンプルコード:

        HttpClient client = HttpClients.createSystem();
    


参考文献
Diagnosing TLS, SSL, and HTTPS

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 Hashing Algorithms
CWE-327: Use of a Broken or Risky Cryptographic Algorithm

Bug Pattern: FILE_UPLOAD_FILENAME

ファイルアップロード 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')

Bug Pattern: REDOS

正規表現 (regexs) は,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')

Bug Pattern: XXE_XMLSTREAMREADER

攻撃

信頼されていないソースから受け取った XML を処理しているときに,XML パーサーが XML エンティティをサポートしていると XML 外部エンティティ (XXE:XML External Entities) 攻撃が発生する可能性があります。

リスク 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

Bug Pattern: XXE_SAXPARSER

攻撃

信頼されていないソースから受け取った XML を処理しているときに,XML パーサーが XML エンティティをサポートしていると XML 外部エンティティ (XXE:XML External Entities) 攻撃が発生する可能性があります。

リスク 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

Bug Pattern: XXE_XMLREADER

攻撃

信頼されていないソースから受け取った XML を処理しているときに,XML パーサーが XML エンティティをサポートしていると XML 外部エンティティ (XXE:XML External Entities) 攻撃が発生する可能性があります。

リスク 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>

Solution

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

Bug Pattern: XXE_DOCUMENT

攻撃

信頼されていないソースから受け取った XML を処理しているときに,XML パーサーが XML エンティティをサポートしていると XML 外部エンティティ (XXE:XML External Entities) 攻撃が発生する可能性があります。

リスク 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>

Solution

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

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: XQuery Injection

Bug Pattern: STRUTS1_ENDPOINT

このクラスは Struts 1 のアクションです。

リクエストがこのコントローラーにルーティングされると,HTTP パラメーター を含む Form オブジェクトが自動的にインスタンス化されます。 これらのパラメーターが安全に使用されているかを確認するためにレビューすべきです。

Bug Pattern: STRUTS2_ENDPOINT

Struts 2 では,エンドポイントは Plain Old Java Object (POJO) です。つまり,インターフェース/クラスを実装/継承する必要がないということです。

リクエストがそのコントローラー (選択されたクラス) にルーティングされると与えられた HTTP パラメーターが自動的にクラスのセッターにマッピングされます。 そのため,フォームにそれらの値が含まれていなくても,このクラスのすべてのセッターは信頼できない入力として見なすべきです。 オブジェクトにそのようなセッターがあるかぎり,攻撃者はリクエストに追加の値を与えるだけで,オブジェクトに設定できます。 これらのパラメーターが安全に使用されているかを確認するためにレビューすべきです。

Bug Pattern: SPRING_ENDPOINT

このクラスは Spring コントローラーです。 RequestMapping (そのショートカットアノテーション GetMappingPostMappingPutMappingDeleteMappingPatchMapping) というアノテーションが付けられたすべてのメソッドは,リモートから到達可能です。 リモートに公開したメソッドが潜在的な攻撃者に公開しても安全であるかを確認するために,このクラスを分析する必要があります。

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)

Bug Pattern: SPRING_CSRF_UNRESTRICTED_REQUEST_MAPPING

RequestMapping というアノテーションが付けられたメソッドは,デフォルトですべての HTTP リクエストメソッドにマッピングされます。 しかし,Spring Security の CSRF 保護は HTTP リクエストメソッド GETHEADTRACEOPTIONS に対して有効になっていません (トークンが漏洩する可能性があるため)。 したがって,RequestMapping でアノテーションされ,マッピングを絞り込まない状態変更メソッド POSTPUTDELETEPATCH は CSRF 攻撃に対して脆弱です。

脆弱なコード:

@Controller
public class UnsafeController {

    @RequestMapping("/path")
    public void writeData() {
        // State-changing operations performed within this method.
    }
}

解決策 (Spring Framework 4.3 以降):

@Controller
public class SafeController {

    /**
     * For methods without side-effects use @GetMapping.
     */
    @GetMapping("/path")
    public String readData() {
        // No state-changing operations performed within this method.
        return "";
    }

    /**
     * For state-changing methods use either @PostMapping, @PutMapping, @DeleteMapping, or @PatchMapping.
     */
    @PostMapping("/path")
    public void writeData() {
        // State-changing operations performed within this method.
    }
}

解決策 (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() {
        // No state-changing operations performed within this method.
        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() {
        // State-changing operations performed within this method.
    }
}

参考文献
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);

カスタムシグネチャを設定する方法 の詳細については,オンラインウィキを参照してください。

参考文献
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')

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

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

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)
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

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

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

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

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

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

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

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 queryies 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

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

動的なコードが評価されています。コードの構築を慎重に分析すべきです。悪意のあるコードの実行は,データ漏洩やオペレーティングシステムが危険にさらされる可能性があります。 ユーザーコードの評価を意図しているなら,適切なサンドボックスを用意すべきです (参考文献を参照)。

If the evaluation of user code is intended, a proper sandboxing should be applied (see references).

リスクのあるコード:

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: 悪意のあるペイロードの例です。示したサンプルは,サンドボックスのルールをテストするために使用される可能性があります。
CWE-94: Improper Control of Generation of Code ('Code Injection')
CWE-95: Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection')

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: 悪意のあるペイロードの例です。示したサンプルは,サンドボックスのルールをテストするために使用される可能性があります。

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: 悪意のあるペイロードの例です。示したサンプルは,サンドボックスのルールをテストするために使用される可能性があります。

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')

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

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')

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>


参考文献
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')

Bug Pattern: EXTERNAL_CONFIG_CONTROL

システム設定の外部制御を許可するとサービスが中断されたり,アプリケーションが予期せぬ悪意のある方法で動作させられたりする可能性があります。 攻撃者は,存在しないカタログ名を指定したり,データベースの権限のない部分に接続することによってエラーを引き起こす可能性があります。


リスクのあるコード:

conn.setCatalog(request.getParameter("catalog"));


参考文献
CWE-15: External Control of System or Configuration Setting

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" として出力されます。

このような状況では,toHexString() を次のように String.format() に置き換えるべきです:

stringBuilder.append( String.format( "%02X", b ) );


参考文献
CWE-704: Incorrect Type Conversion or Cast

Bug Pattern: HAZELCAST_SYMMETRIC_ENCRYPTION

Hazelcast のネットワーク通信は,対称暗号 (おそらく DES または blowfish) を使用するように構成されています。

これらの暗号だけでは,完全性や安全な認証が提供されません。非対称暗号を使用することが望ましいです。


参考文献
WASC-04: Insufficient Transport Layer Protection
Hazelcast Documentation: Encryption
CWE-326: Inadequate Encryption Strength

Bug Pattern: NULL_CIPHER

NullCipher は,本番アプリケーションで意図的に使用されることはほとんどありません。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

Bug Pattern: DES_USAGE

DES と DESede (3DES) は,今のアプリケーションでは強固な暗号とは見なされていません。現在,NIST は DES/3DES の代わりに AES ブロック暗号の使用を推奨しています。

弱いコードの例:

Cipher c = Cipher.getInstance("DESede/ECB/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, k, iv);
byte[] cipherText = c.doFinal(plainText);

解決例:

Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
c.init(Cipher.ENCRYPT_MODE, k, iv);
byte[] cipherText = c.doFinal(plainText);


参考文献
NIST Withdraws Outdated Data Encryption Standard
CWE-326: Inadequate Encryption Strength

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

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

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')

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

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
RSA Laboratories: 3.1.5 How large a key should be used in the RSA cryptosystem?
Wikipedia: Asymmetric algorithm key lengths
CWE-326: Inadequate Encryption Strength
Keylength.com (BlueKrypt): Aggregate key length recommendations.

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')

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')

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: 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

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')

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

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

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

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

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?

Bug Pattern: ECB_MODE

守秘義務のない Electronic Codebook (ECB) モードの代わりに暗号化されたデータのより良い機密性を提供する認証暗号モードを使用すべきです。 特に,ECB モードは毎回同じ入力に対して同じ出力を生成します。たとえば,ユーザーがパスワードを送信するとき,暗号化された値は毎回同じです。 これにより,攻撃者はデータを傍受して再生することができます。

修正するためには,Galois/Counter Mode (GCM) のようなものを代わりに使用すべきです。

リスクのあるコード:

Cipher c = Cipher.getInstance("AES/ECB/NoPadding");
c.init(Cipher.ENCRYPT_MODE, k, iv);
byte[] cipherText = c.doFinal(plainText);

解決策:

Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
c.init(Cipher.ENCRYPT_MODE, k, iv);
byte[] cipherText = c.doFinal(plainText);


参考文献
Wikipedia: Authenticated encryption
NIST: Authenticated Encryption Modes
Wikipedia: Block cipher modes of operation
NIST: Recommendation for Block Cipher Modes of Operation

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

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)。いくつかの予防措置を講ずる必要があります。

これらの要素のいずれかが存在すると ESAPI の暗号化設定も脆弱になる可能性があります:
安全でない設定:
Encryptor.CipherText.useMAC=false

Encryptor.EncryptionAlgorithm=AES
Encryptor.CipherTransformation=AES/CBC/PKCS5Padding

Encryptor.cipher_modes.additional_allowed=CBC

Secure configuration:
#必要
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

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

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

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
OWASP Mobile Top 10 2014-M2: Insecure Data Storage
CWE-312: Cleartext Storage of Sensitive Information

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

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')

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

Bug Pattern: INSECURE_COOKIE

Secure フラグが設定されていない新しいクッキーが作成されています。 Secure フラグは安全でない通信 (http://) のためにクッキーが送信されないようにするためのブラウザへの指示です。

リスクのあるコード:

Cookie cookie = new Cookie("userName",userName);
response.addCookie(cookie);

解決策 (具体的な設定):

Cookie cookie = new Cookie("userName",userName);
cookie.setSecure(true); // Secure flag
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

Bug Pattern: HTTPONLY_COOKIE

HttpOnly が設定されていない新しいクッキーが作成されています。 HttpOnly フラグは,悪意のあるスクリプトによってクッキーが赤色にならないようにするためのブラウザへの指示です。 ユーザーが 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)

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)

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

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

Bug Pattern: MALICIOUS_XSLT

「XSLT (Extensible Stylesheet Language Transformations) は,XML 文書を他のXML文書に変換するための言語です。」[1]
スタイルシートに悪意のある振る舞いを付けることは可能です。 したがって,攻撃者がスタイルシートの内容やソースを制御できると,攻撃者はリモートでコードの実行をトリガーできる可能性があります。[2]

リスクのあるコード:

Source xslt = new StreamSource(new FileInputStream(inputUserFile)); //Dangerous source to validate

Transformer transformer = TransformerFactory.newInstance().newTransformer(xslt);

Source text = new StreamSource(new FileInputStream("/data_2_process.xml"));
transformer.transform(text, new StreamResult(...));

解決策:

解決策は,スタイルシートが安全なソースからロードされていることを確認し,パストラバーサル [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

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

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

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

Bug Pattern: SCALA_XSS_TWIRL

潜在的な XSS を発見しました。クライアントのブラウザで望まれていない JavaScript を実行するために使用される可能性があります。(参考文献を参照)

脆弱なコード:

@(value: Html)

@value

解決策:

@(value: String)

@value

XSSに対する最善の防御は,上記の例のような特定の状況で使える出力エンコーディングです。考慮すべきコンテキストは,HTML,JavaScript,CSS (スタイル),URL の4つです。 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

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に対する最善の防御は,上記の例のような特定の状況で使える出力エンコーディングです。考慮すべきコンテキストは,HTML,JavaScript,CSS (スタイル),URL の4つです。 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

Bug Pattern: TEMPLATE_INJECTION_VELOCITY

Velocity テンプレートエンジンは強力です。条件文,ループ,外部呼び出しなどのロジックを追加することができます。 テンプレート操作をサンドボックスにすることは設計されていません。テンプレートを制御する悪意のあるユーザーは,サーバー側で悪意のあるコードを実行する可能性があります。 Velocity テンプレートはスクリプトとしてみなすべきです。

脆弱なコード:

[...]

Velocity.evaluate(context, swOut, "test", userInput);

解決策:
エンドユーザーが Velocity を使用してテンプレートを操作できないようにします。 テンプレート編集をユーザーに公開する必要があるときは,Handlebars や Mustache などのロジックレステンプレートエンジンを使用することをお勧めします。(参考文献を参照)


参考文献
PortSwigger: Server-Side Template Injection
Handlebars.java

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

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

Bug Pattern: LDAP_ANONYMOUS

適切なアクセス制御がなく,ユーザーの制御下にある値を含む LDAP ステートメントを実行すると,攻撃者は不適切な設定となっている LDAP 環境を悪用する可能性があります。 ctx に対するすべての LDAP クエリは,認証とアクセス制御なしで実行されます。 攻撃者は予期しない方法でこれらのクエリーのいずれかを操作して,ディレクトリのアクセス制御メカニズムにより保護されているレコードにアクセスする可能性があります。

脆弱なコード:

...
env.put(Context.SECURITY_AUTHENTICATION, "none");
DirContext ctx = new InitialDirContext(env);
...

解決策:
LDAP に対する他の認証モードを検討し,適切なアクセス制御メカニズムを確保してください。


参考文献
Ldap Authentication Mechanisms

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

Bug Pattern: COOKIE_PERSISTENT

永続的なクッキーに機密データを長時間保管すると,機密性が損なわれたり,アカウントが悪用される可能性があります。

説明:
永続的クッキーでは有効期限がずっと先に設定されることが多いため,永続的クッキーに個人情報が保管されていると,攻撃者が情報を盗み出すことのできる時間が長くなります。 永続的クッキーは通常,クライアント上のテキストファイルに保存され,被害者のマシンにアクセスできる攻撃者はこの情報を盗む可能性があります。
永続的クッキーは,サイトとやり取りするときのユーザープロファイルとして使用されます。 この追跡データに対して実行される操作によっては,ユーザーの個人情報を盗み出すのに永続的クッキーが使用される可能性があります。

脆弱なコード: 次のコードは,クッキーが1年間で期限切れになるよう設定します。

[...]
Cookie cookie = new Cookie("email", email);
cookie.setMaxAge(60*60*24*365);
[...]

解決策:

  • 永続的クッキーは,必要なときにだけ使用し,最高年齢を制限する
  • 重要なデータに永続的クッキーを使用しない


参考文献
Class Cookie setMaxAge documentation
CWE-539: Information Exposure Through Persistent Cookies

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

Bug Pattern: INSECURE_SMTP_SSL

SSL 接続を確立すると,サーバー ID の確認は無効になります。SSL 接続を有効にする電子メールライブラリによっては,デフォルトでサーバー証明書を検証しません。 これは,すべての証明書を信頼することと同じです。サーバーに接続しようとすると,このアプリケーションは "hackedserver.com" に対して発行された証明書をすぐに受け入れます。 アプリケーションは,ハッキングされているサーバーへの不正な 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

Bug Pattern: AWS_QUERY_INJECTION

ユーザー入力を含む SimpleDB クエリを構築することにより,攻撃者は権限のないレコードを閲覧できます。
次の例では,ユーザーが productCategory を指定できるようにする SimpleDB select() クエリーを動的に構築して実行します。 攻撃者は,クエリーを変更し,顧客 ID に必要な認証をバイパスし,任意の顧客に一致するレコードを表示できます。

脆弱なコード:

...
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

Bug Pattern: BEAN_PROPERTY_INJECTION

攻撃者は,システムの完全性を損なう任意の Bean プロパティを設定できます。Bean population 機能は,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

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

Bug Pattern: SPRING_FILE_DISCLOSURE

ユーザー入力を使用してサーバー側のリダイレクトパスを作成すると,攻撃者はアプリケーションバイナリ (アプリケーションクラスまたはjarファイルを含む) をダウンロードしたり保護されたディレクトリ内の任意のファイルを表示できます。
攻撃者は,重要なファイルの場所と一致するリクエストパラメーターを偽造できます。 たとえば, "http://example.com/?returnURL=WEB-INF/applicationContext.xml" を要求すると,アプリケーションの applicationContext.xml ファイルが表示されます。 攻撃者は,他の設定ファイル,クラスファイル,jar ファイルで参照されている applicationContext.xml を見つけてダウンロードし,機密情報を取得して他の種類の攻撃を開始できます。

脆弱なコード:

...
String returnURL = request.getParameter("returnURL");
return new ModelAndView(returnURL);
...

解決策:
ユーザーが制御する入力を使用してサーバーサイドリダイレクトを構成しないでください。


参考文献
CWE-552: Files or Directories Accessible to External Parties

Bug Pattern: REQUESTDISPATCHER_FILE_DISCLOSURE

ユーザー入力を使用してサーバー側のリダイレクトパスを作成すると,攻撃者はアプリケーションバイナリ (アプリケーションクラスまたはjarファイルを含む) をダウンロードしたり保護されたディレクトリ内の任意のファイルを表示できます。
攻撃者は,重要なファイルの場所と一致するリクエストパラメーターを偽造できます。 たとえば, "http://example.com/?returnURL=WEB-INF/applicationContext.xml" を要求すると,アプリケーションの 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

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)