0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIで作ったアプリ、そのまま公開して大丈夫? ──AIが書いたコードを点検するサンプルレポートが出来るまで

0
Last updated at Posted at 2026-06-23

ChatGPT や Claude で、誰でも素早くアプリが作れる時代になりました。でも「動く」ことと「安全に公開できる」ことは別です。AIは「動く」を優先するので、セキュリティは明示的に頼まないと抜けがちで、しかも作った本人はその抜けに気づきにくい。

私はクラウドソーシングで「AIで作ったアプリの公開前セキュリティ点検」を承っています。本記事は、その納品レポートの見本を、架空アプリを点検する形で作った「制作記」です。

⚠️ この記事のスタンス

  • 題材は実在しない架空アプリです。鍵はダミーです。

サンプル一式(点検対象・改善版・レポート)の置き場所:
https://github.com/sleepycat12341013/security-audit-sample


題材の作り方(透明性のために明記します)

この見本の題材は、デモ用に「AIに、セキュリティをあえて頼まず、よくある作り方のまま=脆弱性を残す形で書かせた」架空のLINE Botです(Node.js・Express・MySQL)。

特殊な細工はしていません。AIに「ポイント機能を作って」とだけ頼むと出てきがちな、ありがちな穴をそのまま残しています。つまりこの Before は「AIに任せた直後のコード」に近いものです。

補足:私自身、下調べや題材生成にAIを使います。AIで作ること自体は否定していません。言いたいのは「AIが作る → 人が点検する」という最後の一手が要る、ということです。


点検の前に:3つのものさし

コードを読む前に、いつもこの3つを持って臨みます。

  1. 「ある」と「効いている」は違う … 対策が「書いてある」ことと「実際に効いている」ことは別。
  2. 信頼境界 … どこから来たものを疑うか。ユーザー側の値は全部疑い、最終判断はサーバーでする。
  3. リスクの置き場所 … 全部完璧にするより、被害の大きい順(個人情報・金銭)から「消す・移す・受容する」を決める。

どんな目線で見るか(6領域)

各領域、Before(AIが書いたままの状態) と、そこで確認する観点を示します。

1. 認証・署名(そのリクエスト、本当に正規の相手から?)

app.post('/webhook', (req, res) => {
  const events = req.body.events;
  events.forEach((event) => { if (event.type === 'message') handleMessage(event); });
  res.sendStatus(200);
});

確認する観点: 届いたリクエストが本当にLINEから来たものか、署名を検証して、失敗時に止めているか。ここが信頼境界の最前線。
🤖 AIあるある: 「まず動くWebhook」を出すので、署名検証は頼まないと付きません

2. 秘密情報の置き場所(鍵はコードに残っていないか)

const CHANNEL_ACCESS_TOKEN = 'ダミー';   // コードに直書き
const db = mysql.createConnection({ user: 'root', password: 'root', /* ... */ });

確認する観点: 鍵・トークン・DB認証がコード・ログ・Git履歴に露出していないか。「消したつもりが履歴に残る」罠も。
🤖 AIあるある: 説明を簡単にするため鍵を直書きで出しがち

3. 認可・なりすまし(他人のデータが見えないか=IDOR)

app.get('/api/points', (req, res) => {
  const userId = req.query.userId;          // クライアントが自由に指定できる値
  db.query(`SELECT * FROM users WHERE line_user_id = '${userId}'`, ...);
});

確認する観点: ログインできること(認証)と、持ち主であること(認可)は別。「誰のデータを返すか」をクライアントの値で決めていないか。
🤖 AIあるある: 「動く」だけなら通るので、頼まないと認可(持ち主チェック)が入りません

4. 入力の検証(サーバー側で最終判断)

db.query(`SELECT points FROM users WHERE line_user_id = '${userId}'`, ...);

確認する観点: ユーザー由来の値をSQLに文字列連結していないかを、1箇所も漏らさず横断して見る。
🤖 AIあるある: クイックな例では文字列連結のまま出てくることがあります。

5. レート制限・濫用耐性

この題材は、実はここはできていました。点検は穴探しではなく、効いている所は効いていると判定するのも仕事です。

app.use(rateLimit({ windowMs: 60 * 1000, max: 60 })); // 1分60回まで

確認する観点: 連打で外部APIコストやDBを食い潰せる入口がないか。全体に上限があり、一次的な歯止めが効いています。

6. LIFF / API

確認する観点: クライアントが送る lineUserId検証せず信用していないか/レスポンスに画面に出す以上のデータ(パスワードハッシュ等)が混ざっていないか/エラーで内部情報を返していないか。
🤖 AIあるある: クライアントの値をそのまま信用したり、SELECT *全部返すコードを出しがちです。


なぜ「自分」や「AIだけ」では確認しきれないのか

ここが一番伝えたい所です。

  • AIに「これ安全?」と聞いても、AIは自分が書いたコードの穴を見落とします。しかも、もっともらしく「大丈夫です」と間違った答えを返すことがあります。
  • 一番こわいのは「書いてあるけど効いていない」状態です。たとえば署名検証が書いてあっても、検証の仕方が違えば素通りします。これは「ある/ない」では分からず、効いているかを確かめないと見抜けません
  • チェックリストを全部✅にしても、その✅が本当に効いているかは別問題。だからこそ、第三者の人の目が要ります。

AIが作る時代だからこそ、最後に「効いているか」を人が確かめる工程が抜けがちなのです。


納品レポートの形(点検でお渡しするもの)

  • 領域ごとに ✅効いている/⚠️要改善 を、該当箇所(ファイル・行)と理由つきで明記
  • 深刻度(最高/高/中)と、直す優先順位(被害の大きい順)
  • 要改善の箇所は、直し方(改善版コードの方向性)までお渡しします=「指摘」を「次の一手」に
  • 必ず免責を添えます(ご依頼日時点・指定範囲の確認であり、すべての脆弱性の不存在を保証するものではありません)

公開前のセルフチェック

公開前に、ご自身で確かめてみてください。1つでも「自信がない」があれば、そこが穴かもしれません。

  • □ 署名検証は、書いてあるだけでなく失敗時に本当に止まっていますか?
  • □ 他人のIDを指定して他人のデータが見える経路は、1つも無いと言い切れますか?
  • □ 鍵は、ログやGit履歴のどこにも残っていませんか?
  • □ ユーザー入力をSQLに連結している箇所は、本当に0ですか?
  • □ 「AIが安全と言った」を、誰か(人)が確かめましたか?

まとめ:AIが作る時代の「最後の一手」

AIは「動く」は作れても、「安全」は頼まないと作りません。本人もAIも、その抜けに気づきにくい。
だから「動くからOK」で公開せず、信頼境界リスクの置き場所で「効いているか」を確かめる──AIが作る → 人が点検する。これがAI時代の最後の一手だと思っています。

公開前点検をクラウドソーシングで承っています。


脆弱性の評価・判定は、すべて筆者本人が行っています。
(題材の生成や下調べにAIを補助的に利用していますが、最終判断は筆者が行っています。)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?