質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PDO

PDO(PHP Data Objects)はPHPのデータベース抽象化レイヤーです。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

3回答

2544閲覧

phpのDB接続で発生するSQLSTATE[42000]のエラーを直したい

mikaduki

総合スコア13

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PDO

PDO(PHP Data Objects)はPHPのデータベース抽象化レイヤーです。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

1クリップ

投稿2018/07/04 08:51

編集2018/07/09 07:41

前提・実現したいこと

phpにおけるsqlインジェクション攻撃の勉強をしていて、実際にphpで脆弱性のあるログイン認証のプログラムを作り、インジェクション攻撃を行っています。
不正ログインができる['OR1'='1 -- ]といったsql文を入力するとログイン成功の文字が返される予定がSQLSTATE[42000]というエラーが出てしまいます。
他のサイトを参考に色々変更しましたが、エラーが改善出来ず、先に進めないといった状況です。どなたかこのエラーの改善方法等を教えてくださると幸いです。どうぞよろしくお願いいたします。

発生している問題・エラーメッセージ

SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'OR1'='1 -- ' AND password = ''' at line 1

php

1<?php 2 // エラーメッセージ 3 $errorMessage = ""; 4 // 画面に表示するため特殊文字をエスケープする 5 $viewUserId = htmlspecialchars(@$_POST["userid"], ENT_QUOTES); 6//POSTの場合は、ログインチェック 7if (strtolower($_SERVER['REQUEST_METHOD']) === 'post'){ 8 $userid = $_POST["userid"]; 9 $password = $_POST["password"]; 10 //データベースへの接続 11 try{ 12 $pdo = new PDO( 13 'mysql:dbname=logintest;host=localhost;charset=utf8mb4','root','', 14 [ 15 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, 16 PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, 17 ] 18 ); 19 //複文の許可 20 $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); 21 //sqlの発行・実行 22 $stmt = $pdo->prepare("SELECT * FROM login WHERE userid = '$userid' AND password = '$password';"); 23 $stmt->execute(); 24 while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { 25 $hozon_pass = $row["password"]; 26 $hozon_id = $row["userid"]; 27 } 28 if ($_POST["userid"] == isset($hozon_id) && $_POST["password"] == isset($hozon_pass)) { 29 echo '<br><span style="color:#0000ff">ログインに成功しました。</span>' ; 30 }else{ 31 echo '<br><span style="color: #ff0000">ログインに失敗しました。</span>'; 32 } 33 $pdo = null; 34 exit(); 35 }catch (PDOException $e) { 36 header('Content-Type: text/plain; charset=UTF-8', true, 500); 37 exit($e->getMessage()); 38 } 39} 40//ログインフォームを表示する 41header('Content-type: text/html; charaset=utf-8'); 42?> 43 44<html> 45 <head> 46 <meta charset="UTF-8"> 47 <title>サンプルログイン</title> 48 </head> 49 <body> 50 <form id="loginForm" name="loginForm" action="<?php print($_SERVER['PHP_SELF']) ?>" method="POST"> 51 <fieldset> 52 <legend>ログインフォーム</legend> 53 <div><?php echo $errorMessage ?></div> 54 <label for="userid">ユーザID</label><input type="text" id="userid" name="userid" value="<?php echo $viewUserId ?>"> 55 <br> 56 <label for="password">パスワード</label><input type="password" id="password" name="password" value=""> 57 <br> 58 <label></label><input type="submit" id="login" name="login" value="ログイン"> 59 </fieldset> 60 </form> 61 </body> 62</html>

補足情報(FW/ツールのバージョンなど)

PHP Version 7.2.5です

or文はuseridの箇所に入れようと思っています。
可能であればuseridとpasswordがわからなくてもor文だけでログインができることが実現できればいいなと思っていて、コメントアウトを利用してpasswordの比較部分を無視するようなsqlが実行したいと思っています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2018/07/04 08:55

どこに入力するのでしょうか。 >['OR1'='1 -- ]
m.ts10806

2018/07/04 09:01

「password」の箇所である前提で回答しました。
guest

回答3

0

ベストアンサー

以下は間違いですね。いろいろなところから混ぜてませんか?

SQL

1'OR1'='1 --

これをパスワードに指定し、ユーザIDには yamada を設定すると、SQL文は以下になります。

SQL

1SELECT * FROM login WHERE userid = 'yamada' AND password = ''OR1'='1 --';

ORと1の間にはスペースが必要ですし、1の後のシングルクォートでもエラーです。
本当は、SQL文の末尾を以下にしたいわけですが

SQL

1... ' OR '1'='1'

パスワードとして「' OR '1'='1'」を指定すると、以下のように末尾のシングルクォートが余計になります。

SQL

1SELECT * FROM login WHERE userid = 'yamada' AND password = '' OR '1'='1'';

これを避けるためには、「' OR '1'='1」とするか…以下になります。

SQL

1SELECT * FROM login WHERE userid = 'yamada' AND password = '' OR '1'='1';

あるいは、SQLコメントを用いて「' OR '1'='1' -- 」とするかです。

SQL

1SELECT * FROM login WHERE userid = 'yamada' AND password = '' OR '1'='1' -- ';

-- から後はコメントなので無視されます。ここで注意点が一つ。MySQLの場合、--の後に空白が必要です。# をコメントとして使う場合は空白は必要ありません。

以上でSQL文のシンタックスエラーは回避されると思いますが、以下の if 文が気になります。

PHP

1if ($_POST["userid"] == isset($hozon_id) && $_POST["password"] == isset($hozon_pass)) {

issetの戻り値は TRUE か FALSE ですから、あまり意味のない比較をしているように見えます。そして、issetがなくPOST値とSQLの結果を比較しているのであれば、POST値「' OR '1='1」等とSQLの戻り値は一致しないでしょうから、不正ログインには至らなくなります。

また、ご質問の趣旨とは無関係ですが、以下にXSS脆弱性がありそうです。

PHP

1<form id="loginForm" name="loginForm" action="<?php print($_SERVER['PHP_SELF']) ?>" method="POST">

詳しくは、「PHP_SELF XSS」で検索してみてください。

投稿2018/07/04 21:47

編集2018/07/04 21:50
ockeghem

総合スコア11701

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mikaduki

2018/07/09 02:03

返信が非常に遅くなり申し訳ありません… ご回答・ご指摘有難うございます。 ご指摘いただいた部分で一つ質問があるのですが、or1=1の文をuseridの欄に記入して、コメントアウトを利用してpasswordの欄が空白でも、ログインができるといったことは可能なのでしょうか。 私としては、useridとpasswordが両方わからなくてもログインが可能ということを実現したいのですが…
ockeghem

2018/07/09 02:51

コメントアウトを利用するのであれば、以下(例)を入力するところです(--の後に空白が必要)が、 ' or 1=1 -- 実際には、パスワード欄を空にするとうまくいきません。その理由は、以下のif文にあります。 if ($_POST["userid"] == isset($hozon_id) && $_POST["password"] == isset($hozon_pass)) { ユーザ名として「' or 1=1 -- 」を入力すると、$hozon_passは値がセットされるので、isset($hozon_pass) は TRUE が帰ります。一方、パスワード欄が空の場合、$_POST["passowrd"] を真偽値と解釈すると FALSE となるので、if文全体としても FALSE ということで、「ログインに失敗しました」となります。 …とこれを見ていて気づきましたが、ユーザ名とパスワードの両方を空にすると、「ログインに成功しました。」となりますね。試してみてください。ただし、これはSQLインジェクションによるものではなく、このif文がおかしいからです。SQLインジェクションとは別の脆弱性ですが、これは意図したものではないと思います。
mikaduki

2018/07/09 08:04

その部分は私がisset関数について勘違いをしてたのでそれによるミスです。 やはりpassword欄を空白のままログインすることは不可能なのでしょうか?
ockeghem

2018/07/09 09:23

> やはりpassword欄を空白のままログインすることは不可能なのでしょうか? いえ、そんなことはないです。あくまで現状のプログラムだとできないということで、プログラムの方を変更すれば、できるようになります。 また、パスワード欄が空白だとだめですが、何か一文字入れればパスワードを知らなくてもログインはできます。なので、空白にこだわることもないように思いますが、いかがでしょうか。
mikaduki

2018/07/10 09:56 編集

素敵なご提案ありがとうございます。 確かに空白にこだわる必要もないので、是非ともそのようにしたいのですが、差し支えなければ変更するプログラムや、それが掲載されているwebサイトを教えていただけないでしょうか。
ockeghem

2018/07/11 05:57

そもそもご質問の動機はどのあたりでしょうか? セキュアコーディングが目的なのであれば、脆弱性以前のバグは修正されたほうがよいと思います。 以下の行は冗長であり、ここにバグがありますが、このバグを修正すると不正ログインもできなくなります。 if ($_POST["userid"] == isset($hozon_id) && $_POST["password"] == isset($hozon_pass)) { なので、この箇所は削除し、その前のところで行のフェッチができたことでログイン成功とみなせば、不自然さのない脆弱性になります。
mikaduki

2018/07/11 07:36 編集

解決しました。 脆弱性を作りたかったので、ご指摘いただいたようにエラーのif文を削除し、ご記述の通りに修正したところ不正ログインができました。 他の皆様からもアドバイスを頂きましたが、回答者様が一番解りやすかったため、ベストアンサーとさせていただきます。 有難う御座いました。
guest

0

MySQLでしたらphpMyAdminありますよね。
実際にその文字列が入った前提でSQLを実行してみると良いですよ。

下記のようになります。

sql

1SELECT * FROM login WHERE userid = 'hoge' AND password = ''OR1'='1 --';

わざわざphpMyAdmin立ち上げるのが面倒であれば構文チェッカーでも良いです。

いずれにしても提示のエラーが出ます。
おそらく or 1 = 1としたいのでしょうけど、ORと1がくっついていますし、それ以外にもシングルクォートの使い方などもおかしいですね。

入力するのは下記になると思います。
' OR '1' = '1

投稿2018/07/04 09:00

編集2018/07/05 03:09
m.ts10806

総合スコア80842

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ockeghem

2018/07/05 03:07

' OR 1 =1 だと、もともとあるシングルクォートが残り、エラーになりますよね
m.ts10806

2018/07/05 03:08

あ、そうでした。失礼しました。。 ご指摘ありがとうございます。
mikaduki

2018/07/09 02:04 編集

返信が非常に遅れてしまい申し訳ございません… ご返答有難うございます。 ご指摘いただいたor文を入力してもログインに失敗しました。
m.ts10806

2018/07/09 01:55

実際に実行されたSQL文をご提示ください。 いきなりプログラムを実行されるよりも、一度SQLを直接実行して試してみたほうが良いです。
mikaduki

2018/07/09 02:07

クエリチェッカーでもphpmyadminでもやはりエラーがでます。
m.ts10806

2018/07/09 02:10

実際に実行されたSQL文をご提示ください。(2回目) 質問者さんが実際に行ったことと、回答者の意図とは 完全に合致しているとは限りません。
m.ts10806

2018/07/09 02:12

とはいえ、エラーが出るのでしたら、そのエラーを直せばよいだけですが・・・。
mikaduki

2018/07/09 02:15

SELECT * FROM login WHERE userid = ' OR '1' = '1 AND password = です
m.ts10806

2018/07/09 02:22

なるほど。 私、「質問への追記・修正、ベストアンサー選択の依頼」にて「どこに入力するのでしょうか」に回答いただけてないので「「password」の箇所である前提で回答しました。」としています。 「ユーザID」である旨を質問本文に追記しておいてください。 回答内容が違ってきます。 しかし SELECT * FROM login WHERE userid = '$userid' AND password = '$password'; に対して「' OR '1' = '1」を入れたら SELECT * FROM login WHERE userid = '' OR '1' = '1' AND password = '入れたパスワード'; になるはずですが・・。
mikaduki

2018/07/09 02:33

答えるのが遅れましたが、or文はuseridの箇所に入れようと思っています。 私としてはuseridとpasswordがわからなくてもor文だけでログインができることが実現できればいいなと思っていて、コメントアウトを利用してpasswordの比較部分を無視するようなsqlが実行したいと思っています。
m.ts10806

2018/07/09 02:38

「ユーザID」である旨を質問本文に追記しておいてください。(2回目) では、こうなれば良いはずですね。 SELECT * FROM login WHERE userid = '' OR '1' = '1' -- ' AND password = '入れたパスワード'; ということで画面から入力するのは ' OR '1' = '1' -- ただし、物事には順番があります。 1.質問を編集して要件を具体化する 2.SQLを実行してエラーなく完了することを確かめる 3.画面から入力して結果を確認する
m.ts10806

2018/07/09 02:40

質問は編集できます。 個々の回答に対してのコメントで要件を書いても、他の見ている人には基本的に伝わりません。 まず見るのは質問本文です
guest

0

'OR1'='1 --

SQLてきに間違ってないですか?

select * from hogehoge where user_name = ''OR1'='1 --
ってなっちゃうとふつうに構文エラーっぽいです。コピペミスでなければの話ですけど。

投稿2018/07/04 09:02

perpouh

総合スコア299

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mikaduki

2018/07/09 02:08

返信が非常に遅くなり申し訳ございません ご回答有難うございます。 確かに改めて見るとシングルコートの位置がおかしいですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問