[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
>SQLインジェクション(英: SQL Injection)とは、アプリケーションのセキュリティ上の不備を意図的に利用し、アプリケーションが想定しないSQL文を実行させることにより、データベースシステムを不正に操作する攻撃方法のこと。また、その攻撃を可能とする脆弱性のことである。
SQLに別のSQL文が「注入 (inject)」されることから、「ダイレクトSQLコマンドインジェクション」もしくは「SQL注入」と呼ばれることもある。
SQLインジェクション攻撃への対策|脆弱性を悪用する仕組みと具体例
>しかし、C#の例と同様に「’or’1’=’1」を使うことでユーザ認証を回避できます。
WHERE user=’USER01′ and pass=”PASSWORD1”or’1’=’1′;
>同じように、以下のようなSQL文を使うことでデータの消去も可能です。
name’; DELETE FROM items; SELECT * FROM items WHERE ‘a’=’a
データをまるっと消してしまうこともできるのか。それは対策するしかないな。
https://blogs.mcafee.jp/sql-injection-prevention
またエラーだ。
呼び出すメンバがないというらしい。
・接続ができないとでるらしい
・またはsql文がおかしい
$pdoをつくるまでのあたりがまちがってるとでるらしいが。SQLはただしいがデータがないときはこういうエラーではないらしい
→
FROMがFORMになっていた
名前:nobita
パス:nobinobi
でログインしてみましょう
できた。(脆弱なシステムが)
ではこれからクラッキングをしてみますよ。
・$sql文をつくるときにそのまま使っているのが超まずい
・md5なのもまずいが
ここまで
--->index2.php
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ログイン認証</title>
<link rel="stylesheet" href="auth.css">
</head>
<body>
<div id="container">
<form method="post" action="auth.php">
<table>
<tr>
<th><label for="u_id">ユーザー名</th>
<td><input type="text" name="u_id" id="u_id"></td>
</tr>
<tr>
<th><label for="pass">パスワード</label></th>
<td><input type="password" name="pass" id="pass"></td>
</tr>
</table>
<p><button type="submit">認証</button></p>
</form>
</div>
</body>
</html>
--->auth.php
<?php
session_start();
//いつもの
$user="root";
$dbpass="";
$host="localhost";
$dbname="auth";
$dsn="mysql:host={$host};dbname={$dbname};charset=utf8";
$pdo=new PDO($dsn, $user, $dbpass);
$pass = md5($_POST["pass"]);
$sql="SELECT nickname FROM users WHERE u_id='" . $_POST["u_id"] . "'
AND pass='" . $pass . "'";
//echo $sql;
//print_r($_POST);
$res= $pdo->query($sql);
$row= $res->fetch(PDO::FETCH_ASSOC);
//echo $row["nickname"];
//認証するかどうか
if($row["nickname"]){ //nicknameが存在すれば
//認証
$_SESSION["login"]=true;
$_SESSION["name"]=$row["nickname"];
header("Location: mypage.php");
}else{
//認証不可
header("Location: index2.php");
}
?>
さて、
SELECT nickname FROM users WHERE u_id="nobita" OR '1'='1' AND pass="usono_pass";
1=1はすべて真だから「条件に該当」とみなされる
これをDBのSQLタブでうちこむとちゃんとデータがでてきてしまう
Fatal error: Uncaught Error: Call to a member function fetch() on bool
in C:\xampp\htdocs\php\makino\auth\auth.php:19 Stack trace: #0 {main}
thrown in C:\xampp\htdocs\php\makino\auth\auth.php on line 19
入力しているものがまずかったようですね
ユーザー名 nobita' OR '1'='1
パスワード てきとう
→
ログインできる
コマンドプロンプトでいれる
スペースで切り離したホスト名(www.yahoo.co.jp)とかを指定
Microsoft Windows [Version 10.0.18362.592]
(c) 2019 Microsoft Corporation. All rights reserved.
C:\Users\web.DESKTOP-EQR2U6K>ping yahoo.co.jp
yahoo.co.jp [183.79.135.206]に ping を送信しています 32 バイトのデータ:
192.168.11.1 からの応答: 宛先ホストに到達できません。
192.168.11.1 からの応答: 宛先ホストに到達できません。
192.168.11.1 からの応答: 宛先ホストに到達できません。
192.168.11.1 からの応答: 宛先ホストに到達できません。
183.79.135.206 の ping 統計:
パケット数: 送信 = 4、受信 = 4、損失 = 0 (0% の損失)、
C:\Users\web.DESKTOP-EQR2U6K>
ip ver6が提供するサービスだけが開けてver.4がだめという謎の現象が起こっているらしい
SQLインジェクション
わざとmd5で安全性の低いデータを作ってみますよ
<p><?php echo md5("nobinobi") ?></p>
<!--わざとセキュリティの低いのを出力し、コピー
d0209b61369398a6d2469738c16ffdbf
→
DB→挿入→
INSERT INTO `users` (`u_id`, `pass`, `nickname`) VALUES ('nobita',
'd0209b61369398a6d2469738c16ffdbf', 'のび太');
→サクラ、index.php
を
index2.phpで別名保存
いまindex2.phpはパスワードハッシュしてるので、
<!DOCTYPE html>より上を全部削除
このページは窓口だけにし、認証は別の画面にしましょう
<form method="post" action="auth.php">
と変更
認証ボタンの次の行とかもカット
このページのphpを全部取る形
・u_idとpassが飛んでくるのでそれを処理したい
新規でauth.php
かならずu_idとpassが来ている前提で記述するよ。テストなんで。
脆弱なものをわざとつくるよ
こういう構造
ここまで
--->index2.php
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ログイン認証</title>
<link rel="stylesheet" href="auth.css">
</head>
<body>
<div id="container">
<form method="post" action="auth.php">
<table>
<tr>
<th><label for="u_id">ユーザー名</th>
<td><input type="text" name="u_id" id="u_id"></td>
</tr>
<tr>
<th><label for="pass">パスワード</label></th>
<td><input type="password" name="pass" id="pass"></td>
</tr>
</table>
<p><button type="submit">認証</button></p>
</form>
</div>
</body>
</html>
--->auth.php
<?php
//いつもの
$user="root";
$dbpass="";
$host="localhost";
$dbname="auth";
$dsn="mysql:host={$host};dbname={$dbname};charset=utf8";
$pdo=new PDO($dsn, $user, $dbpass);
//つくりたいsqlは以下の通り
//SELECT nickname FROM users WHERE u_id='nobita' AND pass='hoehoehoe'";
$sql="SELECT nickname FORM users WHERE u_id='" . $_POST["u_id"] . "'
AND pass='" . $_POST["pass"] . "'";
echo $sql;
?>
たいへんややこしい""の開け閉じ。黄色の部分がかたまりでドットでつないでいる。
--->出力
SELECT nickname FORM users WHERE u_id='nobita' AND pass='aaa';
しかしさきDBに登録したのは脆弱とはいえmd5でハッシュしてるからこのままだと機能ないね
こう書き換えますよ
$pdo=new PDO($dsn, $user, $dbpass);
$pass = md5($_POST["pass"]); //わざとです。脆弱なハッシュ
//つくりたいsqlは以下の通り
//SELECT nickname FROM users WHERE u_id='nobita' AND pass='hoehoehoe'";
$sql="SELECT nickname FORM users WHERE u_id='" . $_POST["u_id"] . "'
AND pass='" . $pass . "'";
echo $sql;
実行結果
SELECT nickname FORM users WHERE u_id='nobita' AND
pass='47bce5c74f589f4867dbd57e9ca9f808'
ちょっと前まではみんなこーゆー危険な書き方をしていたらしい
ぷりぺあーどならぷりぺあーどをつかうが
直にsqlを実行するときはくえりーめそっどをつかうよ
$res=$pdo->query($sql);
>ユーザー入力を受け取ってSQL文を動的に生成する場合は プリペアドステートメント と プレースホルダ を使わなければなりません.
プレースホルダ:
直訳すると「場所取り」.何かユーザ入力を当てはめる場所としてあらかじめ確保しておくもの.
プリペアドステートメント:
直訳すると「予約文」.文を予約したもの.通常,「予約文」は「場所取り」を使うために作られる.もし「場所取り」が無ければ普通に PDO::query などで実行するだけで十分なためである.
fetch
>カーソルをずらしながら,指定したフェッチモードで1行ずつ取得していきます.
引数を省略した場合はデフォルトフェッチモードが使用される.
全ての取得が終わると常に false を返す.
>プレースホルダは、SQL文の中で「ユーザーが入力した値」を代入する箇所に使用します。
例えば以下のようなSQL文があった場合、
INSERT INTO user (user_screen_name) VALUES ('ハルジオン');
末尾にある「ハルジオン」という部分は、ユーザーによって入力される値です。(逆に、他の部分は固定文となります)
プレースホルダを使わずに、上記のようにユーザーから入力された値を直接SQLに結合してしまうと、万が一、悪意のあるユーザーによって不正な値が入力された場合、SQL文が壊れてしまったり、別のSQL文に変えられてしまう恐れがあります。
こういった攻撃手法を「SQLインジェクション」と言います。
これに対策するために、以下のようにプレースホルダを使います。
INSERT INTO user (user_screen_name) VALUES (:user_screen_name);
プレースホルダを使うと、その部分はあくまで「値」として処理し、
SQL文として実行されることはなくなりますので、安全に実行出来るというわけです。