SQL-injectionが通用するサイトを作った話

はじめに

この記事はプロコンゼミ(SPC同好会) その1 advent Calendar 2018 12日目の記事です

その1 1日目, その2,2日目にも記事を書いています

直前まで何を書くか決まっておらず迷走した結果sqlインジェクションが通るウェブサイトを作ることにしました()

とりあえずSQL,SQLインジェクションについて軽く触れます、SQLが何だがわかってる人は適当に読み流してもらえると。

SQLとは

SQLは、関係データベース管理システム (RDBMS) において、データの操作や定義を行うためのデータベース言語(問い合わせ言語)、ドメイン固有言語である。エドガー・F・コッドによって考案された関係データベースの関係モデルにおける演算体系である、関係代数と関係論理(関係計算)にある程度基づいている。 データベース言語の国際標準としてのSQLは何かの略語ではない。

by wikipedia
らしいです、はい

データベースにアクセスするための言語というかそのようなものです、基本情報の午後試験で選択できたりします、
ただ最近(?)は直接人間がsqlを書くことは少なくrailsのactiverecordやDjangoのそれなどORM(Object-relational mapping)を使うことが多いです、実際今年度のプロコンでも自由はSequerize,課題はDjangoのORMを使っていました。

SQLが直接使われなくなった原因は単純に書きにくいというのもありますが”SQLインジェクション”を引き起こしやすくなることが大きいのではないでしょうか

SQLの構文

SQLインジェクションの説明をする前にSQL自体について説明したいと思います、私自身SQL初心者と言っても良い部類だと思うので間違っているかもしれません、あくまで参考程度に…

SQL系データベース(RDB)ではデータを表のように管理します。

Users

id name password
1 Tarou adfskj
2 Hanako asdffjf
3 saitou asdfhsA
4 tanaka ASdsf

一つの表のことをテーブル,列のことをカラムといいます
この場合はusers テーブル, name カラムみたいな感じです

1
2
# users テーブルから idカラムとnameカラムを取得
select id,name from users;

出力 =>

id name
1 Tarou
2 Hanako
3 saitou
4 tanaka
1
2
# users テーブルから idカラムが1である要素のnameカラムを取得
select name from users where id=1;

出力 =>

name
Tarou

まあなんかこんな感じでSQLを使うと任意のデータを取り出したりデータを追加したり、上書きしたりすることができます

SQLインジェクションとは

やっとSQLインジェクションの解説まで到達しました、
SQLインジェクションとはその名の通りSQLにinject(注入する)攻撃です。
先程まではSQLを手で打っている想定でしたが実際はアプリケーションの中で実行します、すると次のようなコードを書きたくなります

(sqlは仮定上の関数です、実際には色々なライブラリがあります)

1
result = sql('select name from users where id ="' + $id + '" and password="'+ $password + '";')

(usersテーブルからidが”変数id”でpasswordが”変数password”であるものの名前を取得)

一見うまく行きそうに見えますがこのコードはSQLインジェクション攻撃を受ける余地があります

変数 passwordにユーザから入力された文字列をそのまま代入している場合、次のようなsql文が発行される可能性があります

$id に 1 , $passwordに 1" or "1"="1が代入された場合

1
select name from users where id="1" and password ="1" or "1" = "1";

これでは本来はpasswordの値が合わないとアクセスできないデータに "1" = "1"である限りアクセスされてしまいます、これがSQLインジェクションです、SQLに悪意のある文字列を”注入”しているわけです。

通常はユーザーが入力した文字列の中にSQLで意味を持つ(記号,文)が入っていないか確認をします、railsのActiverecordやほとんどのORMがこれを自動でやってくれます。

作ったもの

https://sql-injection.u-t.me

さてやっと本題(?)です、現在ではほぼ全てのサイトでSQLインジェクションに対して対策が取られています(少なくとも自分はそう信じたいです)なのであえてSQLインジェクション攻撃が通用するウェブサイトを作ったわけです(?)。

もちろん実際に運用しているわけではなく、データベースも本来はサーバーで動かすのですがフロントで動かしていて、リロードするたびにデータはリセットされます。
また、SQLインジェクションがわかりやすいように()発行されたSQL文が確認できるようになっています。

SQLインジェクション攻撃の仕方は少なくとも先程説明した 1" or "1" and "1では通るようになっています。user名はadminnormaluserです、ウェブサイトと言ってもログイン機能しかないんですけどね…

技術的なお話

sql.js

流石にサーバーで動かしてるsqlを脆弱にするのは気が引けるのでフロントでsqlを実行しています、内部ではsqliteが動いてるらしいです、はじめはweb splというブラウザ標準の機能を使う予定だったのですが、どうやらwebsqlは非推奨になったらしいです、なのでsql.jsを使っています、人類なんでも.jsつければいいとおもってるでしょ。

Nuxt.js

フロントはNuxtを使っています、プロコン期間中はあまり気にしなかったけどNuxtとても良い、フロントのコードをガンガンかけて気持ちがいい。
なにぶん全然ネタが思いつかなくて短時間で作ったのでクオリティは察してください。

GitHub Pages

ホスティングは我らがGitHubPagesを使っています。超楽、便利

あとGitHub Pagesでデプロイしてるので当然リポジトリも公開しています
github

おわりに

なんというか、完全にAdventarのためのネタですが、まあ強制的にアウトプットしないといけない良い機会だと考えましょう。

最後にadventartのリンク色々

その1
その2

明日(12/13)の担当は
その1 => @chuson
その2 => @rei
です