不適切な権限の処理

不適切な権限検証と拒否処理

説明

ユーザーの権限を正しく検証しなかったり、必要な権限のない要求を拒否しなかったりすると、認可に問題が生じます。その結果、許可されていないユーザーが制限されたリソースや機能にアクセスするおそれがあります。

想定される影響

  • 権限昇格: 許可されていないユーザーが管理操作を行う可能性があります。
  • 情報漏えい: アクセス権限のないユーザーに機密データが渡るおそれがあります。
  • サービス停止: システムリソースへの不正な操作で、サービスが停止する可能性があります。

対処方法

  • 重要な機能やリソースへのアクセスごとに権限を検証してください。
  • 権限のない要求は操作を実行する前に拒否し、適切なHTTPエラーステータスを返してください。エラー文言を変えるだけではアクセス制御になりません。
  • Django、Flask、FastAPIなどの認証・認可機能を利用してください。

例

認証設定、セッション管理、ユーザー検索を省略した抜粋です。Flask-Loginでは適切なユーザーローダーとログイン設定が必要です。is_admin はクライアント入力ではなく、信頼できる権限情報から取得してください。

Django

変更前

python
# 権限検証が不適切なDjangoコード
from django.http import HttpResponse

def view_sensitive_data(request):
    if request.user.username != 'admin':
        return HttpResponse("Not authorized")
    # 機密データの処理
    return HttpResponse("Sensitive data")

変更後

python
# 権限検証を改善したDjangoコード
from django.http import HttpResponse
from django.contrib.auth.decorators import login_required, user_passes_test

@login_required
@user_passes_test(lambda u: u.is_superuser)
def view_sensitive_data(request):
    # 機密データの処理
    return HttpResponse("Sensitive data")

説明:

  • 変更前: ユーザー名を管理者権限と同一視しています。この文字列比較だけで、ユーザー登録や名前の変更、必要な権限を安全に管理できると考えないでください。
  • 変更後: Djangoの login_required と user_passes_test によって、認証済みでスーパーユーザーの条件を満たすユーザーにアクセスを制限します。

Flask

変更前

python
# 検証が不適切なFlaskコード
from flask import Flask, request

app = Flask(__name__)

@app.route('/sensitive')
def view_sensitive_data():
    if request.args.get('user') != 'admin':
        return "Not authorized"
    # 機密データの処理
    return "Sensitive data"

変更後

python
# 検証を改善したFlaskコード
from flask import Flask, request, abort
from flask_login import login_required, current_user

app = Flask(__name__)

@app.route('/sensitive')
@login_required
def view_sensitive_data():
    if not current_user.is_admin:
        return abort(403)
    # 機密データの処理
    return "Sensitive data"

説明:

  • 変更前: user クエリパラメーターはクライアントが指定できるため、管理者権限の根拠になりません。
  • 変更後: Flask-Loginの current_user を使い、認証済みユーザーに必要な権限がなければ拒否します。

FastAPI

変更前

python
# 検証が不適切なFastAPIコード
from fastapi import FastAPI, Request, HTTPException

app = FastAPI()

@app.get("/sensitive")
async def view_sensitive_data(request: Request):
    if request.query_params.get('user') != 'admin':
        return {"detail": "Not authorized"}
    # 機密データの処理
    return {"detail": "Sensitive data"}

変更後

python
# 検証を改善したFastAPIコード
from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel

app = FastAPI()

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

class User(BaseModel):
    username: str
    is_admin: bool

def get_current_user(token: str = Depends(oauth2_scheme)):
    # トークン検証とユーザー検索を実装するまではアクセスを拒否します。
    raise HTTPException(status_code=401, detail="Token verification is not configured")

@app.get("/sensitive")
async def view_sensitive_data(current_user: User = Depends(get_current_user)):
    if not current_user.is_admin:
        raise HTTPException(status_code=403, detail="Not authorized")
    # 機密データの処理
    return {"detail": "Sensitive data"}

説明:

  • 変更前: URLでクライアントが指定したユーザー名を、アクセス制御の根拠にしています。
  • 変更後: OAuth2PasswordBearer はBearerトークンを取り出すだけで、有効性は検証しません。この抜粋は検証が実装されるまでアクセスを拒否します。get_current_user でトークンを検証し、信頼できるユーザーストアから権限を取得した後にだけ User を返すよう実装してください。

参考資料