Skip to main content

Pythonにおける安全でない直接オブジェクト参照(IDOR)の発見と修正

著者

Keshav Malik

feature python linting

2023年7月19日

0 分で読めます

安全でない直接オブジェクト参照(IDOR)は、システムの実装に認可チェックがないため、攻撃者が機密性の高いオブジェクトやリソースに直接アクセスし、操作できてしまうセキュリティ脆弱性です。たとえば、ユーザーが指定した入力に基づいてオブジェクトへ直接アクセスできるアプリケーションでは、攻撃者が認可を回避できるため、IDORが発生する可能性があります。

IDORの脆弱性を理解する

Pythonアプリケーションが扱う機密データの機密性、完全性、可用性を維持するには、IDORに対処する必要があります。開発者は、不正アクセスを防ぎ、ユーザーの信頼を維持するとともに、深刻な経済的・法的影響を回避するために、IDORの脆弱性を理解する必要があります。

IDORの種類

IDORには、アプリケーションの実装や機能に応じてさまざまな形態があります。

オブジェクト参照を利用したIDOR

このタイプのIDORは、攻撃者が権限のないオブジェクトにアクセスしたり、変更したりできる場合に発生します。よくある例として、Webアプリケーションがexample.com/accounts?id={account_id}のような単純なリクエストを通じて、銀行口座などの機密データへのアクセスを許可しているケースがあります。アプリケーションがリクエスト元の権限を適切に検証しなければ、不正なユーザーが口座情報を閲覧または操作できてしまいます。

ファイル参照を利用したIDOR

このタイプのIDORでは、ファイルが不正に取得されます。たとえば、チャットアプリケーションが機密性の高い会話ログを番号が連番になったファイルとして保存している場合、攻撃者はexample.com/1.log、example.com/2.logなど、番号を変えたリクエストを送ることで、他人のプライベートな会話にアクセスできる可能性があります。

ブラインドIDOR

ブラインドIDORとは、不正な変更が行われていても、その悪用がサーバーのレスポンスに直接現れないケースを指します。ブラインドIDORでは、攻撃者は他のユーザーのプライベートなデータを閲覧せずに変更できます。たとえば、Webアプリケーションがexample.com/users/update?id={user_id}のようなAPI呼び出しによるプロフィール設定の変更を許可している場合、攻撃者はリクエスト内のuser_idを操作して、データを直接閲覧することなくユーザーのプロフィール設定を変更できてしまいます。

コード内のIDOR脆弱性を見つけるための一般的なパターン

コード内のIDOR脆弱性を検出するには、注意深く確認し、一般的なパターンを理解しておく必要があります。

  • アクセス制御の欠如:ユーザーの認可を確認せず、ユーザー入力を使ってリソースに直接アクセスするアプリケーションには、IDOR脆弱性がある可能性があります。

  • 推測可能な識別子:連番の整数(user_id=99001)や短い文字列(user_id=user1)など、簡単に推測できる識別子は、アプリケーションのIDOR脆弱性のリスクを高めます。Universally Unique Identifier(UUID)など、推測が困難な識別子を使用することで、このリスクを軽減できます。

  • ファイルへの直接アクセス:URLやリクエストパラメーターを通じて、画像やCSVファイルなどのリソースにユーザーが直接アクセスできるアプリケーションは、IDORに対して脆弱です。ユーザーがファイルに直接アクセスできないよう、適切な制御の仕組みを確実に導入する必要があります。

FastAPIでIDOR脆弱性のあるPythonアプリケーションを作成する

このセクションでは、PythonフレームワークのFastAPIを使って、IDOR脆弱性のあるWeb APIを作成します。その後、脆弱性の修正方法を確認します。

このハンズオンチュートリアルを進めるには、お使いのマシンにPython 3.xがインストールされていることを確認してください。

始める前に

まず、新しいアプリケーションを用意します。プロジェクト用のディレクトリを作成し、そのディレクトリに移動します。

mkdir fastapi-app; cd fastapi-app

次に、以下のコマンドでFastAPI、Uvicorn、SQLAlchemy、SQLiteをインストールします。

pip install fastapi uvicorn sqlalchemy

最後に、プロジェクトディレクトリにmain.pyという名前のファイルを作成します。

FastAPIで脆弱性のあるAPIを作成する

ディレクトリ構成と必要なパッケージを用意できたので、次はIDOR脆弱性を含むコードを書きます。以下のコードをmain.pyにコピーしてください。

from fastapi import FastAPI, HTTPException, Depends
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session

app = FastAPI()

# SQLite database configuration
DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

# User model
class User(Base):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True, index=True)
    uuid = Column(String, unique=True, index=True)
    username = Column(String, unique=True, index=True)
    email = Column(String, unique=True, index=True)

Base.metadata.create_all(bind=engine)

# Dependency for database session
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

@app.get("/users/{user_id}")
async def get_user_by_id(user_id: int, db: Session = Depends(get_db)):
    user = db.query(User).filter(User.id == user_id).first()
    if user is None:
        raise HTTPException(status_code=404, detail="User not found")
    return user

IDOR脆弱性があるのは/users/user_idエンドポイントです。アプリケーションにはアクセス制御がないため、URL内のuser_idを変更するだけで、誰でも他のユーザーのデータを閲覧できます。

IDOR脆弱性の特定と修正

それでは、FastAPIアプリケーションのIDORセキュリティ上の欠陥を見つけて修正しましょう。

脆弱性を見つける

IDOR脆弱性を特定するには、コード内の特定のパターンを探す必要があります。FastAPIアプリケーションでは、次の理由からIDOR脆弱性の可能性がある/users/{user_id}エンドポイントを調べます。

  • 保護されていない直接オブジェクト参照:get_user_by_id関数では、user_idパラメーターがデータベース内のUserオブジェクトを直接参照しています。この参照を保護するアクセス制御の仕組みがないため、クライアントはリクエスト内のuser_idの値を操作して、他のユーザーのデータにアクセスできます。

  • 認可の欠如:同じget_user_by_id関数内で、リクエストしたユーザーが要求されたユーザーデータにアクセスする権限を持つかどうかを確認していません。user_idパラメーターを操作すれば、誰でも他のユーザーのデータにアクセスできます。

脆弱なコードを修正する

IDOR脆弱性を修正するには、適切なアクセス制御チェックを行うよう/users/{user_id}エンドポイントを更新する必要があります。

認証済みユーザーを想定し、URL内のuser_idがそのユーザーのIDと一致する場合にのみアクセスを許可するようにします。説明のため、認証済みユーザーのIDは1とします。更新後のコードは次のとおりです。

@app.get("/users/{user_id}")
async def get_secure_user(user_id: int, db: Session = Depends(get_db)):
    # Assume user authentication and authorization are performed here
    authenticated_user_id = "hbecec-edeek-wxwexe-cdcece" # better to use UUIDs

    if authenticated_user_id != user_id:
        raise HTTPException(status_code=403, detail="Not authorized to access this user")

    user = db.query(User).filter(User.id == user_id).first()
    if user is None:
        raise HTTPException(status_code=404, detail="User not found")
    return user

このコードでは、URLのuser_idとauthenticated_user_idを比較するアクセス制御チェックを追加しました。IDが一致しない場合、アプリケーションはHTTP 403 Forbiddenエラーを返します。このエラーによって不正なユーザーが他のユーザーの情報にアクセスできなくなり、IDOR脆弱性を修正できます。

Snykでセキュリティ問題を検出・修正する

Snykは、ソフトウェア構成分析(SCA)と静的アプリケーションセキュリティテスト(SAST)に対応したセキュリティソリューションです。Snykを使って、FastAPIアプリケーションのセキュリティ問題を見つけて修正しましょう。

Snyk CLIのインストールと認証

まず、ドキュメントのインストールガイドに従って、お使いのマシンにSnyk CLIをインストールします。

CLIのインストール後、Snykアカウントを認証する必要があります。ターミナルでsnyk authコマンドを実行するとブラウザーウィンドウが開き、GitHubまたはGoogleアカウントでサインインできます。

依存関係の脆弱性をスキャンする

プロジェクトでサードパーティーライブラリの脆弱性をスキャンするには、requirements.txtファイルが必要です。以下のコマンドでrequirements.txtを作成します。

pip freeze > requirements.txt

次に、ターミナルで以下のコマンドを実行し、プロジェクトの依存関係にある脆弱性をスキャンします。

snyk test --file=requirements.txt --skip-unresolved

このコマンドは依存関係を分析し、脆弱性を特定して説明します。深刻度や修正方法も表示されます。たとえば、starlette@0.14.2に中程度の深刻度のサービス拒否(DoS)脆弱性が見つかることがあります。

注:必須パッケージが不足している場合、Snykはプロジェクトをスキャンできません。–skip-unresolvedフラグを指定すると、この動作を上書きできます。

Snykで脆弱性を修正する

Snykは脆弱性の修正にも役立ちます。snyk fixコマンドを使うと、検出された問題の一部を自動的に修正できます。Snykは影響を受ける依存関係を安全なバージョンにアップグレードまたはパッチ適用し、アプリケーションを最新かつ安全な状態に保ちます。

Snyk Codeで静的コード解析を行う

Snykは、強力な静的アプリケーションセキュリティテスト(SAST)ソリューションも提供しています。snyk codeコマンドでアプリケーションのコードを分析し、セキュリティ問題を特定して、修正方法の詳細を確認できます。

snyk codeを使うには、ターミナルで以下のコマンドを実行します。

snyk code test

Snyk Codeはコードベースを詳細に分析し、存在するセキュリティ脆弱性を明らかにします。また、問題の修正方法も提案するため、安全で信頼性の高いアプリケーションの維持に役立ちます。

IDOR脆弱性を理解する

開発者として、アプリケーションのセキュリティを確保する必要があります。IDORはWebアプリケーションを脅かすため、見つけて修正する方法を学ぶことが大切です。IDOR脆弱性を正しく理解すれば、高いパフォーマンスとセキュリティを両立するPythonアプリケーションを構築できます。

このチュートリアルでは、PythonアプリケーションのIDOR脆弱性を見つけて修正する方法を学びました。また、Snykを使って、プロジェクトの依存関係やアプリケーションコード自体に潜むセキュリティリスクを特定し、対処する方法も確認しました。Snykは強力なセキュリティツールです。開発プロセスに取り入れることで、コードを堅牢に保つための保護をさらに強化できます。

Snykの機能をさらに詳しく知るには、無料トライアルをお試しください。

CTFを始めよう

オンデマンドのバーチャル入門ワークショップで、CTFチャレンジの解き方を学びましょう。