説明
ユーザーの権限を正しく検証しなかったり、必要な権限のない要求を拒否しなかったりすると、認可に問題が生じます。その結果、許可されていないユーザーが制限されたリソースや機能にアクセスするおそれがあります。
想定される影響
- 権限昇格: 許可されていないユーザーが管理操作を行う可能性があります。
- 情報漏えい: アクセス権限のないユーザーに機密データが渡るおそれがあります。
- サービス停止: システムリソースへの不正な操作で、サービスが停止する可能性があります。
対処方法
- 重要な機能やリソースへのアクセスごとに権限を検証してください。
- 権限のない要求は操作を実行する前に拒否し、適切な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を返すよう実装してください。