आधुनिक वेब अनुप्रयोगों के लिए एपीआई सुरक्षा सबसे महत्वपूर्ण चिंता है। 2026 में, एपीआई प्रमाणीकरण, उपयोगकर्ता डेटा, भुगतान और बुनियादी ढांचे को संभालते हैं – जिससे वे प्राथमिक हमले की सतह बन जाते हैं। यह मार्गदर्शिका उत्पादन में आपके एपीआई की सुरक्षा के लिए ओडब्ल्यूएएसपी एपीआई सुरक्षा शीर्ष 10, कार्यान्वयन पैटर्न और टूल को कवर करती है।
📋 Table of Contents
OWASP एपीआई सुरक्षा शीर्ष 10 (2023)
- टूटी हुई वस्तु स्तर प्राधिकरण (BOLA)
- टूटा हुआ प्रमाणीकरण
- टूटी हुई वस्तु संपत्ति स्तर प्राधिकरण
- अप्रतिबंधित संसाधन उपभोग
- टूटा हुआ फ़ंक्शन स्तर प्राधिकरण
- संवेदनशील व्यावसायिक प्रवाह तक अप्रतिबंधित पहुंच
- सर्वर-साइड अनुरोध जालसाजी (एसएसआरएफ)
- सुरक्षा गलत कॉन्फ़िगरेशन
- अनुचित इन्वेंटरी प्रबंधन
- एपीआई का असुरक्षित उपभोग
प्रमाणीकरण: जेडब्ल्यूटी सर्वोत्तम प्रथाएँ
from datetime import datetime, timedelta, timezone
from typing import Optional
import jwt
import secrets
import hashlib
SECRET_KEY = secrets.token_hex(32) # Store in env var!
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE = timedelta(minutes=15)
REFRESH_TOKEN_EXPIRE = timedelta(days=30)
def create_access_token(user_id: int, scopes: list[str] = []) -> str:
payload = {
"sub": str(user_id),
"type": "access",
"scopes": scopes,
"iat": datetime.now(timezone.utc),
"exp": datetime.now(timezone.utc) + ACCESS_TOKEN_EXPIRE,
"jti": secrets.token_hex(16), # JWT ID for revocation
}
return jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)
def verify_token(token: str) -> dict:
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
# Check if token is revoked (requires Redis/DB lookup)
if is_token_revoked(payload["jti"]):
raise jwt.InvalidTokenError("Token revoked")
return payload
except jwt.ExpiredSignatureError:
raise ValueError("Token expired")
except jwt.InvalidTokenError as e:
raise ValueError(f"Invalid token: {e}")
# NEVER store secrets in JWTs
# ALWAYS verify signature
# Use short expiry + refresh tokens
# Store sensitive data server-side, not in JWT
दर सीमित करना
from fastapi import FastAPI, Request, HTTPException
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
limiter = Limiter(key_func=get_remote_address)
app = FastAPI()
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
@app.post("/api/auth/login")
@limiter.limit("5/minute") # 5 login attempts per minute per IP
async def login(request: Request, credentials: LoginCredentials):
pass
@app.get("/api/users")
@limiter.limit("100/minute") # 100 requests per minute
async def list_users(request: Request, current_user: User = Depends(get_current_user)):
pass
# Also implement:
# - Per-user rate limits (not just per-IP)
# - Exponential backoff on repeated auth failures
# - Account lockout after N failed attempts
इनपुट सत्यापन
from pydantic import BaseModel, EmailStr, Field, validator, field_validator
import re
class CreateUserRequest(BaseModel):
name: str = Field(min_length=2, max_length=50, pattern=r"^[a-zA-Z\s'-]+$")
email: EmailStr
password: str = Field(min_length=8, max_length=128)
age: int = Field(ge=13, le=120)
@field_validator("password")
@classmethod
def password_strength(cls, v: str) -> str:
if not re.search(r"[A-Z]", v):
raise ValueError("Password needs uppercase letter")
if not re.search(r"[0-9]", v):
raise ValueError("Password needs a digit")
if not re.search(r"[!@#$%^&*]", v):
raise ValueError("Password needs special character")
return v
@field_validator("name")
@classmethod
def sanitize_name(cls, v: str) -> str:
# Strip dangerous characters even if pattern matches
return v.strip()
# NEVER trust client input
# Validate all fields: type, format, length, range
# Reject unexpected fields (use strict mode)
# Sanitize before storage and display
वस्तु-स्तरीय प्राधिकरण (BOLA रोकथाम)
# VULNERABLE: Trusts user-supplied ID
@app.get("/api/invoices/{invoice_id}")
async def get_invoice(invoice_id: int, current_user: User = Depends(get_current_user)):
return db.invoices.get(invoice_id) # ANY user can access ANY invoice!
# SECURE: Always verify ownership
@app.get("/api/invoices/{invoice_id}")
async def get_invoice(invoice_id: int, current_user: User = Depends(get_current_user)):
invoice = db.invoices.get(invoice_id)
if not invoice:
raise HTTPException(404, "Not found")
if invoice.user_id != current_user.id and current_user.role != "admin":
raise HTTPException(403, "Forbidden") # Don't reveal existence to unauthorized users
return invoice
# BEST PRACTICE: Filter by user_id in query
@app.get("/api/invoices/{invoice_id}")
async def get_invoice(invoice_id: int, current_user: User = Depends(get_current_user)):
invoice = db.invoices.get_for_user(invoice_id, user_id=current_user.id)
if not invoice:
raise HTTPException(404, "Not found")
return invoice
सुरक्षा शीर्षलेख
from fastapi import FastAPI
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware
from starlette.middleware.cors import CORSMiddleware
app = FastAPI()
# HTTPS redirect (production only)
app.add_middleware(HTTPSRedirectMiddleware)
# CORS: be specific, never use "*"
app.add_middleware(
CORSMiddleware,
allow_origins=["https://myapp.com", "https://www.myapp.com"],
allow_credentials=True,
allow_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
allow_headers=["Authorization", "Content-Type"],
)
# Security headers middleware
@app.middleware("http")
async def add_security_headers(request, call_next):
response = await call_next(request)
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["X-XSS-Protection"] = "1; mode=block"
response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
response.headers["Content-Security-Policy"] = "default-src 'self'"
# Remove server header
response.headers.pop("server", None)
return response
संवेदनशील डेटा सुरक्षा
import bcrypt
import secrets
from cryptography.fernet import Fernet
# Password hashing (NEVER store plaintext)
def hash_password(password: str) -> str:
return bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12)).decode()
def verify_password(password: str, hashed: str) -> bool:
return bcrypt.checkpw(password.encode(), hashed.encode())
# Encrypt sensitive data (credit cards, SSNs, etc.)
ENCRYPTION_KEY = Fernet.generate_key() # Store in secrets manager!
cipher = Fernet(ENCRYPTION_KEY)
def encrypt_pii(data: str) -> str:
return cipher.encrypt(data.encode()).decode()
def decrypt_pii(encrypted: str) -> str:
return cipher.decrypt(encrypted.encode()).decode()
# API key generation
def generate_api_key() -> str:
return "tp_" + secrets.token_urlsafe(32)
# Mask sensitive data in responses
def mask_credit_card(card: str) -> str:
return "*" * 12 + card[-4:]
def mask_email(email: str) -> str:
user, domain = email.split("@")
return user[:2] + "***@" + domain
एपीआई सुरक्षा चेकलिस्ट
- सभी समापन बिंदुओं को प्रमाणीकरण की आवश्यकता होती है (सार्वजनिक को छोड़कर)
- प्रत्येक डेटा एक्सेस पर ऑब्जेक्ट-स्तरीय प्राधिकरण
- प्रमाणीकरण, खोज और महंगे समापन बिंदुओं पर दर सीमित करना
- सख्त स्कीमा के साथ इनपुट सत्यापन (पाइडेंटिक, ज़ॉड, जॉय)
- केवल HTTPS, HSTS सक्षम
- सुरक्षा शीर्षलेख (एक्स-फ़्रेम-विकल्प, सीएसपी, सीओआरएस)
- बीक्रिप्ट के साथ पासवर्ड हैश किया गया (लागत कारक 12+)
- पर्यावरण चर या गुप्त प्रबंधक में रहस्य
- SQL पैरामीटरयुक्त क्वेरीज़ (कोई स्ट्रिंग संयोजन नहीं)
- संवेदनशील कार्यों के लिए ऑडिट लॉग
- बहिष्करण की अनुमति देने के लिए एपीआई संस्करण
- निर्भरता स्कैनिंग (पिप-ऑडिट, एनपीएम ऑडिट)
2026 में एपीआई सुरक्षा के लिए गहन रक्षा की आवश्यकता है। कोई भी एक तकनीक पर्याप्त नहीं है – प्रमाणीकरण, प्राधिकरण, दर सीमित करना, इनपुट सत्यापन और निगरानी को संयोजित करें। अपनी सीआई पाइपलाइन में स्वचालित सुरक्षा स्कैन (एसएएसटी, डीएएसटी) चलाएं और तिमाही आधार पर ओडब्ल्यूएएसपी टॉप 10 की समीक्षा करें। उल्लंघन की लागत उचित सुरक्षा कार्यान्वयन की लागत से कहीं अधिक है।
🔗 Share this article
✍️ Leave a Comment