社内LT用資料なのでマストでおさえておかなきゃいけない重要なところだけ。
Never trust user input
-- モット・セキュアナコード
SQLインジェクション(SQLi)
問題点
プログラムがユーザからの入力値を受け取り、その値をパラメータとしてSQLを実行する際に、悪意あるSQL文がInjectされ意図しない結果をまねくこと。
対策
Prepared Statementを使うこと。
# bad example
$query = "SELECT * FROM user WHERE id=".$_GET['id']
# what if $_GET['id'] comes with "1; DELETE FROM user"??
# good example
$sth = $dbh->prepare('SELECT * FROM user WHERE id = ?');
$sth->execute(array(11));
クロスサイトスクリプティング(XSS)
問題点
HTMLにプログラムで扱った値を表示する際に、Javascriptを埋め込まれ、Cookieを盗まれたり悪意ある動作をさせてしまう。
対策
エスケープしましょう。DB上に格納するときにエスケープするのではなく、HTMLで表示するときにエスケープするように。
<?php
function h($str) {
return htmlspecialchars($str)
}
?>
<body>
<?php echo h($value) ?>
</body>
JavascriptもDOMの使い方によっては脆弱性になりえるので注意。
$.ajax({
url: /someurl,
success: function(data) {
var str = data.sample_string;
$("#foo").text(str); // Good!
$("#foo").html(str); // Badddd!
$("#foo").append(str); // Badddd! You need to escape by yourself.
}
});
var h = (function (String) {
var escapeMap = {
'&': '&',
"'": ''',
'`': '`',
'"': '"',
'<': '<',
'>': '>'
};
var escapeReg = '[';
var reg;
for (var p in escapeMap) {
if (escapeMap.hasOwnProperty(p)) {
escapeReg += p;
}
}
escapeReg += ']';
reg = new RegExp(escapeReg, 'g');
return function h (str) {
str = (str === null || str === undefined) ? '' : '' + str;
return str.replace(reg, function (match) {
return escapeMap[match];
});
};
}(String));
クロスサイトリクエストフォージュリ(CSRF)
問題点
たとえばアカウントのステータスを変更するプログラムがあったとして、そのURLが
http://www.example.com/user/status_change?id=a123&new_status=1
だったとき、悪意あるユーザがこのIDを自由に変更できてしまうと、権限を超えた操作ができてしまう。
対策
アクセスしているユーザしかわからない値をもちいて、リクエストを受け付けるときに必ずその値をValidateする。
最近のフレームワークはたいていCSRFに対応していのでその機能を用いること。
// this sample is just ONLY sample. Use the feature which is implemented in framework.
$csrf_token_base = "some_random_string_with_enough_length"
$action_name = "user_status_change"; // unique value that identifies page relatively.
$base = $_SESSION['id'].$action_name; // use something unique for each user which only user can know such as session_id stored in cookie.
$crumb = hash_hmac('sha256', $base, $csrf_token_base);
if (count($_POST) == 0) {
view('user_status_change.html', $crumb);
} else {
$p_crumb = $_POST['csrf_crumb'];
if ($p_crumb == $check_crumb) {
// OK!!
} else {
// Not Good!!
}
}
<form action="prog.php" method="post">
<input type="hidden" name="csrf_crumb" value="<?php echo $crumb?>">
<select name="new_status">
<option value="start">Start</option>
<option value="stop">Stop</option>
</select>
<input type="submit" value="change">
</form>
Cookie
- httponly : JavascriptからCookieにアクセスできないようにする。XSSの対策に有効。
- secure : HTTPSでのみやりとりされるCookie
パスワードの取り扱い
- bcryptベースでハッシュを行う
- 復号できるようにはしない。一方向ハッシュ
参考資料
参考資料:
https://www.owasp.org/images/7/79/OWASP_Top_10_2013_JPN.pdf