ネクストライブのリスクマネジメントチームのRです。
開発現場では、さまざまなソースコードを見かけます。今回は、第一弾として、セキュリティ事故に繋がるような事例を紹介します。業界に新しく来る方はぜひ読んで、セキュリティ意識を高くしてください。
システムをリリース後、不具合によりシステムが停止してしまう場合があります。その不具合の原因がバグはもちろんのことですが、テスト不足によりバグが発見されなかった場合は、トラブルとなり、最悪は損害賠償が発生します。
import java.util.*;
public class Main {
public static void main(String[] args) throws Exception {
// ランダムに値を取得
Random random = new Random();
int value = random.nextInt(10);
System.out.println("value: " + value);
check(value);
}
// 偶数かどうか判定する関数
private static void check(int value) {
// 偶数かどうか判定
boolean flg = value % 2 == 0;
if (flg) {
System.out.println("パターン:偶数");
} else {
System.out.println("パターン:奇数");
}
}
}
上記の例は、偶数か奇数かを判断する関数です。この場合は、最低でも2パターンのテストを実施しましょう。時間に余裕があれば、各パターンのテストをしてもいいですが、最低でもifの分岐パターンのテストを実施していれば十分なことが多いです。もちろん、if文がネストしている場合、その分テストパターンを増やしましょう。そのため、ネストは少ない方が、テストパターンが少なく済むので、なるべくシンプルに実装することをオススメします。経験が浅い方は、必ず先輩にテスト仕様書や実施方法についてレビューをしてもらい、テスト結果のエビデンスを残すようにしましょう。
テストパターン | 期待結果 |
---|---|
偶数の時 | 「パターン:偶数」が出力されること |
奇数の時 | 「パターン:奇数」が出力されること |
余裕があれば、想定されるパターンのテストをしてもよいでしょう。また、実装工数は必要ですが、自動テストにすると各パターンのテストが自動化されるので、テスト工数をトータルでは削減することが可能です。
テストパターン | 期待結果 |
---|---|
0の時 | 「パターン:偶数」が出力されること |
1の時 | 「パターン:奇数」が出力されること |
2の時 | 「パターン:偶数」が出力されること |
3の時 | 「パターン:奇数」が出力されること |
.. | .. |
9の時 | 「パターン:奇数」が出力されること |
新人の中には、SQLインジェクションという言葉を知らない方もいます。そのような方が実装するソースコードは要注意です。たとえば、パラメーターを使ってSQL文を作成するロジックにて、インジェクションが潜んでいるケースが多いです。
※外部のサイトへ、意図的にSQLインジェクションを試すことは、不正アクセス禁止法違反となるので、試してはいけません
// formからのPOSTテストを行うため、テスト用に意図的に値を設定
$_POST['id'] = 'hoge';
$_POST['password'] = 'foo';
print_r($_POST);
// 出力
// > Array
// > (
// > [id] => hoge
// > [password] => foo
// > )
$sql = "SELECT id, password FROM members WHERE id = '${_POST['id']}' AND password = '${_POST['password']}'";
echo($sql);
// 出力
// > SELECT id, password FROM members WHERE id = 'hoge' AND password = 'foo'
上記のように、正常な値であれば問題がありません。しかし、エスケープ処理をしていない場合、SQL文を書き換えてしまうと、不正ログインができてしまいます。
// 不正ログインの例
$_POST['id'] = "hoge' AND '1' = '1'--";
$_POST['password'] = "foo";
print_r($_POST);
// 出力
// > Array
// > (
// > [id] => hoge' AND '1' = '1'--
// > [password] => foo
// > )
$sql = "SELECT id, password FROM members WHERE id = '${_POST['id']}' AND password = '${_POST['password']}'";
echo($sql);
// 出力
// > SELECT id, password FROM members WHERE id = 'hoge' AND '1' = '1'--' AND password = 'foo'
上記の場合、パスワード部分がコメントアウトされ、任意のログインIDでログインができてしまいます。これを防ぐために、各フレームワークのエスケープ処理を実装する必要があります。単純な文字列結合は注意しましょう。
一般的にデータベースにパスワードを保存する時は、暗号化して保存するのが一般的です。それは、暗号化されている場合、万が一パスワードが漏洩しても、復号が必要となるため、すぐに悪用されることがないからです。しかし、平文で保存されている場合は、ID(メールアドレス)とパスワードが漏洩した場合、すぐに悪用(他サービスへのリスト攻撃など)が可能となってしまいます。また、自身が取り扱うパスワードの取り扱いも注意しましょう。不要になればアカウントを削除したり、書類をシュレッダーしましょう。
login_id | password |
---|---|
test1 | test1234 |
test2 | 12345678 |
test3 | password |
login_id | password |
---|---|
test1 | ecb666d778725ec.. |
test2 | 2c26b46b68ffc68.. |
test3 | 512eea46ceb3921.. |
システムをリリース(デプロイ)するとき、手順誤りによって、⻑時間システムが停止してしまう場合があります。小さい現場になるほど、マニュアル不足であったり、専任者が休みなどによる不在で、対応したことのない方が急遽作業をすることがあります。その時に、トラブルが発生してしまい、元に戻せなくなってしまう場合があります。
そのようなことにならないように、運用に関するマニュアルを整備する工数は用意しておくことをオススメします。
開発現場でのセキュリティ要件は、現場によって要件が異なるので独習ではなかなか身に付けることができません。必ず、プロジェクトが変わった時は、チームにセキュリティ要件や方針を確認して、開発することが大切です。たった1行のソースコードから、損害賠償へと繋がることもあるため、不安な場合は、徹底したレビューとテストを実施することが大切です。