پایگاه داده مشتریان یک فروشگاه اینترنتی کوچک نشت میکند. چند هفته بعد، یک سرویس پخش ویدیو با موجی از ورود به حسابهایی روبهرو میشود که هرگز مشکلی نداشتهاند؛ یک پلتفرم بازی همین را میبیند و یک بانک هم. هیچکدام از آنها هک نشدهاند. همان جفتهای ایمیل و رمز عبور فروشگاه بهسادگی در صفحههای ورود آنها کار کردند، چون بسیاری از مردم برای همهجا یک رمز به کار میبرند.
این نوشته credential stuffing را از نگاه مدافع بررسی میکند: تفاوت آن با brute force و password spraying، دلیل اینکه از هزاران نشانی IP میرسد، نشانههایی که در لاگهای شما میگذارد، کنترلهایی که جلوی آن را میگیرند و کارهایی که کاربران میتوانند انجام دهند. دو نمونه کوتاه پایتون هم آمده است که هر دو دفاعیاند.
credential stuffing چیست؟
credential stuffing استفاده دوباره و در مقیاس بزرگ از اطلاعات ورود دزدیدهشده است. مهاجم از جفتهایی شروع میکند که واقعی بودنشان از پیش معلوم است، چون از نشت قبلی یک سرویس دیگر به دست آمدهاند، و آنها را با نرمافزار خودکار به فرم ورود میفرستد. بیشتر جفتها شکست میخورند. آنهایی که کار میکنند متعلق به حسابهاییاند که صاحبانشان در سایت نشتکرده و سایت هدف یک رمز به کار بردهاند.
OWASP Credential Stuffing Prevention Cheat Sheet آن را آزمودن جفتهای نام کاربری و رمز عبوری تعریف میکند که «از نشت یک سایت دیگر به دست آمدهاند». رمزهای خود سایت هدف دزدیده نشدهاند و کد آن هم ایرادی ندارد؛ نقطه ضعف، تکرار رمز عبور است.
آنچه مهاجم میخواهد تصاحب حساب (account takeover یا ATO) است: ورودی معتبر به حسابی که چیز باارزشی در آن ذخیره شده است. این میتواند امتیاز وفاداری، کارت پرداخت ذخیرهشده، موجودی کارت هدیه، دادههای شخصی یا صرفاً حسابی مورد اعتماد برای فرستادن هرزنامه باشد. حسابهای تصاحبشده اغلب دوباره فروخته میشوند.
حمله credential stuffing چگونه کار میکند؟
در نگاه کلی، یک حمله از پنج مرحله میگذرد. شناختن آنها به شما کمک میکند تصمیم بگیرید هر دفاع را کجا قرار دهید.
- نشتی در جای دیگر. یک سرویس به خطر میافتد و فهرست کاربرانش، با ایمیلها و رمزها (یا هش رمزهایی که بعدها شکسته شدهاند)، دستبهدست میشود.
- گردآوری. جفتهای نشتکرده از رخدادهای بسیار در فهرستهای بزرگ ادغام میشوند. نشتهای قدیمی سالها ارزش خود را حفظ میکنند، چون بسیاری از مردم هرگز رمز تکراری را عوض نمیکنند.
- خودکارسازی. نرمافزار جفتها را به فرم ورود یا API ورود هدف میفرستد، بسیار سریعتر از آنچه انسان بتواند تایپ کند.
- پخش کردن. برای گریز از محدودیتهای ساده مبتنی بر IP، درخواستها میان نشانیهای IP بسیار پخش میشوند، اغلب از راه باتنتهایی از دستگاههای آلوده یا شبکههای پروکسی اجارهای، طوری که هر نشانی فقط چند تلاش میفرستد.
- بهرهبرداری از موفقیتها. جفتهایی که کار میکنند از نظر ارزش بررسی و سپس استفاده یا فروخته میشوند. برخی مهاجمان بیدرنگ ایمیل و رمز را عوض میکنند تا صاحب واقعی را بیرون نگه دارند.
مرحله 1 روی سرور کس دیگری رخ میدهد. دفاعهای شما در مرحلههای 3 تا 5 قرار میگیرند: ورود خودکار را پرهزینه کنید، کاری کنید که رمز درست بهتنهایی کافی نباشد و تصاحب حساب را زود ببینید. بررسی رمزها در برابر فهرستهای نشت، مرحله 2 را به زیان مهاجم برمیگرداند.
مقایسه credential stuffing با brute force و password spraying
هر سه حمله صفحههای ورود را نشانه میگیرند، اما ورودیهای متفاوتی به کار میبرند و ردهای متفاوتی به جا میگذارند. تعریفهای زیر از cheat sheet سازمان OWASP پیروی میکنند.
| حمله | چه چیزی امتحان میشود | الگو | نرخ موفقیت معمول هر تلاش | دفاع اصلی |
|---|---|---|---|---|
| brute force | رمزهای بسیار روی یک حساب | یک حساب، رمزهای بسیار | بسیار پایین، مگر رمز ضعیف باشد | محدودیت تلاش برای هر حساب، رمزهای بلند |
| password spraying | یک رمز رایج روی حسابهای بسیار | حسابهای بسیار، یک یا چند رمز | پایین، به رمزهای ضعیف تکیه دارد | فهرست مسدودی رمزهای رایج، MFA |
| credential stuffing | جفتهای واقعی نشتکرده، هر کدام یک بار | حسابهای بسیار، برای هر کدام یک رمز | بالاتر، چون هر جفت جایی واقعی بوده است | MFA، بررسی رمزهای نشتکرده، تشخیص بات |
قفل کردن حساب پس از پنج رمز نادرست جلوی brute force را میگیرد. اما روی credential stuffing تقریباً اثری ندارد، چون هر حساب معمولاً فقط یک تلاش میبیند.
چرا پروکسیها و IPهای مسکونی در این حملهها دیده میشوند
مسدود کردن یک نشانی IP پس از بیست ورود ناموفق مثل یک محافظت به نظر میرسد، پس مهاجمان درخواستها را از نشانیهای بسیار عبور میدهند: روترهای خانگی ربودهشده، دستگاههای آلوده، سرورهای ابری و شبکههای پروکسی. مسدود کردن نشانیهای اتصال خانگی دشوار است، چون مشتریان واقعی هم ممکن است از آنها استفاده کنند.
به همین دلیل cheat sheet سازمان OWASP میگوید مسدودسازی IP و اعتبار IP «نباید تنها دفاع یا دفاع اصلی باشند». سه مشکل عملی وجود دارد:
- حجم کم برای هر نشانی. وقتی هر نشانی یک یا دو تلاش میفرستد، هیچ آستانه مبتنی بر IP فعال نمیشود.
- نشانیهای مشترک. اپراتورهای موبایل و بسیاری از ارائهدهندگان اینترنت خانگی مشتریان زیادی را پشت یک نشانی عمومی قرار میدهند (NAT در سطح اپراتور یا CGNAT). مسدود کردن آن نشانی میتواند کاربران واقعی را بیرون بگذارد.
- جابهجایی مداوم. نشانیها سریع عوض میشوند، پس فهرست مسدودی تقریباً همان لحظهای که نوشته میشود کهنه است.
با این حال داده IP همچنان بهعنوان یکی از چند سیگنال مفید است. یک IP fraud score یا قرار داشتن نشانی در یک فهرست سیاه IP میتواند ریسک یک ورود را بالا ببرد و بهجای مسدودسازی مستقیم، یک بررسی اضافه را فعال کند.
نکتهای درباره شبکه خودمان: شرایط خدمات Proxynet تلاش برای دسترسی غیرمجاز را ممنوع میکند و حسابهایی که قواعد استفاده مجاز را زیر پا بگذارند ممکن است بدون اطلاع قبلی تعلیق شوند. کاربردهای مشروع، مانند آزمودن سایت خودتان از کشورهای دیگر، در صفحه امنیت داده ما آمده است.
نشانههایی که میگویند زیر حملهاید
هیچ نشانهای بهتنهایی حمله را ثابت نمیکند، اما چند نشانه با هم بهسختی نادیده میمانند. اینها ارزش آن را دارند که روی داشبورد بیایند:
- جهش در نرخ ورودهای ناموفق. بیشتر جفتهای نشتکرده جور درنمیآیند، پس یک موج حمله نرخی را که معمولاً ثابت است ناگهان بالا میبرد.
- شکستهای فراوان از نوع «کاربر ناشناس». فهرستهای نشتکرده ایمیلهایی دارند که هرگز در سایت شما ثبتنام نکردهاند.
- حسابهای بسیار، هر کدام یک تلاش. نسبت نامهای کاربری متمایز به تلاشها نزدیک به یک است، درست برعکس الگوی brute force.
- نشانیهای IP بسیار، هر کدام با تلاشهای اندک، اغلب از شبکههایی که بهندرت کاربر واقعی برای شما میفرستند.
- اثر انگشت یکسان کلاینت در هزاران کاربر «متفاوت»؛ نوشته تشخیص بات چگونه کار میکند این سیگنالها را توضیح میدهد.
- ورود بدون بازدید صفحه. درخواستهایی که مستقیم به API ورود میروند، بیآنکه صفحه ورود، اسکریپتها یا تصویرهایش بارگذاری شود.
- آنچه پس از ورود موفق رخ میدهد. ورودی که در چند ثانیه با تغییر ایمیل، رمز یا اطلاعات برداشت وجه دنبال میشود.
کاربران اغلب زودتر از شما متوجه میشوند: یک هشدار ورود مشکوک از بانک یا ایمیل «ورود تازه» که خودشان انجام ندادهاند. گزارش دادن را برایشان آسان کنید.
چگونه جلوی credential stuffing را در سایت خود بگیرید
cheat sheet سازمان OWASP دفاعها را تقریباً به ترتیب ارزش فهرست میکند. فهرست زیر همان روح را حفظ میکند و آنچه NIST SP 800-63B (ویرایش 4، نهایی از اوت 2025) از سامانههای رمز عبور میخواهد به آن میافزاید.
- احراز هویت چندعاملی. OWASP احراز هویت چندعاملی (MFA) را «با فاصله، بهترین دفاع» در برابر حملههای رمز عبور مینامد: رمز نشتکرده درست دیگر کافی نیست. آن را برای حسابهای مدیریتی و کارهای پرخطر الزامی کنید و وقتی نشانههای بالا فعال شدند، به کارش بیندازید.
- passkeyها. یک passkey رمز عبور را با یک جفت کلید جایگزین میکند که روی دستگاه کاربر نگه داشته میشود. FIDO Alliance آنها را در برابر فیشینگ مقاوم میداند و روی سرور شما هیچ راز مشترکی نیست که نشت کند یا دوباره استفاده شود. حسابی که فقط با passkey وارد میشود چیزی برای امتحان کردن در credential stuffing باقی نمیگذارد.
- بررسی رمزهای نشتکرده. NIST SP 800-63B در بخش 3.1.1.2 میگوید تأییدکنندهها باید هر رمز تازه را با فهرست مسدودی از مقادیر «پرکاربرد، قابلانتظار یا بهخطرافتاده» مقایسه کنند. هنگام ثبتنام و هنگام تغییر رمز بررسی کنید و هر وقت نشانهای از به خطر افتادن بود، تغییر رمز را اجباری کنید.
- محدودیت تلاشی که حساب را دنبال کند، نه فقط IP را. بخش 3.2.2 از NIST تلاشهای ناموفق پیاپی روی یک حساب را به حداکثر 100 محدود میکند. آن را با محدودیت برای هر دستگاه، هر بازه IP و هر endpoint ورود ترکیب کنید و بهجای قفل کردن حساب، پاسخها را گامبهگام کُند کنید.
- مدیریت بات. بررسی کنید کلاینت JavaScript اجرا میکند یا نه و آیا اثر انگشت اتصالش با مرورگری که ادعا میکند هماهنگ است. CAPTCHA یک سرعتگیر است، نه همه دفاع.
- پاسخ یکسان برای هر شکست. برای «رمز نادرست» و «کاربر وجود ندارد» پیام یکسان و زمان پاسخ مشابه برگردانید تا فرم ورود برای فهمیدن اینکه کدام ایمیلها حساب دارند به کار نیاید.
- به کاربران خبر دهید و حساب را پس از ورود زیر نظر بگیرید. برای ورود از دستگاه تازه و تغییرات حساب هشدار بفرستید و پیش از این تغییرات عامل دوم را بخواهید.
کد: بررسی رمزهای نشتکرده با k-anonymity
API سرویس Pwned Passwords از Have I Been Pwned به شما امکان میدهد یک رمز را در برابر نشتهای شناختهشده بررسی کنید، بیآنکه خود رمز یا حتی هش کامل آن را بفرستید. فقط پنج نویسه نخست هش SHA-1 را میفرستید؛ سرویس همه پسوندهای هش را که با آنها شروع میشوند همراه با شمارش برمیگرداند و شما پسوند خود را بهصورت محلی جستوجو میکنید. این همان مدل k-anonymity (ناشناسی k) است. API بازهها به کلید API نیاز ندارد و هدر Add-Padding ردیفهای فریبنده (با شمارش 0) اضافه میکند تا اندازه پاسخ چیزی را لو ندهد.
import hashlib
import time
import urllib.error
import urllib.request
API = "https://api.pwnedpasswords.com/range/"
def breach_count(password: str, retries: int = 3) -> int:
"""Return how many times a password appears in Pwned Passwords (0 = not found)."""
digest = hashlib.sha1(password.encode("utf-8")).hexdigest().upper()
prefix, suffix = digest[:5], digest[5:]
request = urllib.request.Request(
API + prefix,
headers={"User-Agent": "example-signup-check", "Add-Padding": "true"},
)
for attempt in range(retries):
try:
with urllib.request.urlopen(request, timeout=5) as response:
body = response.read().decode("utf-8")
break
except (urllib.error.URLError, TimeoutError):
if attempt == retries - 1:
raise
time.sleep(2 ** attempt)
for line in body.splitlines():
candidate, _, count = line.partition(":")
if candidate == suffix:
return int(count) # padded rows have count 0
return 0
if __name__ == "__main__":
for pw in ["password123", "correct horse battery staple", "vX9#qL2-mT8!rW4zK7"]:
hits = breach_count(pw)
verdict = "reject: seen in breaches" if hits else "not in the breach list"
print(f"{pw!r}: {hits} -> {verdict}")با اجرای آن، دو رمز نخست بهعنوان یافتشده برمیگردند، با شمارشهایی که با بهروزرسانی مجموعه داده بیشتر میشوند؛ رشته تصادفی 0 برمیگرداند. در فرم ثبتنام، breach_count را روی سرور فراخوانی کنید، هر نتیجه غیرصفر را با پیامی روشن رد کنید و از پیش تصمیم بگیرید اگر API در دسترس نبود چه شود.
کد: شناسایی موج credential stuffing در لاگهای ورود
بیشتر سایتها هر تلاش ورود را از قبل ثبت میکنند. اسکریپت زیر یک لاگ CSV با ستونهای time، ip، username و result را میخواند، تلاشها را بر اساس دقیقه گروهبندی میکند و دقیقههایی را که نرخ شکست در آنها غیرعادی است، همراه با سهم کاربران ناشناس و شمار حسابها و نشانیهای متمایز، چاپ میکند.
import csv
from collections import defaultdict
ALERT_FAIL_RATE = 0.50
MIN_ATTEMPTS = 50
# Group login attempts into one-minute buckets.
buckets = defaultdict(lambda: {"total": 0, "failed": 0, "unknown": 0, "users": set(), "ips": set()})
with open("logins.csv", newline="") as f:
for row in csv.DictReader(f):
b = buckets[row["time"][:16]] # "2026-09-28T10:41"
b["total"] += 1
b["users"].add(row["username"])
b["ips"].add(row["ip"])
if row["result"] != "ok":
b["failed"] += 1
if row["result"] == "unknown_user":
b["unknown"] += 1
for minute in sorted(buckets):
b = buckets[minute]
fail_rate = b["failed"] / b["total"]
unknown_share = b["unknown"] / b["total"]
if b["total"] >= MIN_ATTEMPTS and fail_rate >= ALERT_FAIL_RATE:
print(f"{minute} attempts={b['total']} failed={fail_rate:.0%} "
f"unknown-user={unknown_share:.0%} accounts={len(b['users'])} ips={len(b['ips'])}")روی یک لاگ آزمایشی با ترافیک عادی و یک موج شبیهسازیشده، خروجی اینگونه است:
2026-09-28T10:40 attempts=80 failed=78% unknown-user=49% accounts=80 ips=69
2026-09-28T10:41 attempts=80 failed=79% unknown-user=45% accounts=80 ips=70هشتاد حساب، تقریباً همین تعداد نشانی و نیمی از نامهای کاربری ناشناس: این الگوی credential stuffing است. آستانهها را بر پایه ترافیک عادی خودتان تنظیم کنید.
کاربران چه کاری میتوانند انجام دهند
credential stuffing فقط روی رمزهای تکراری کار میکند، پس کنترل واقعی آن در دست کاربران است.
- از مدیر رمز عبور استفاده کنید تا هر سایت رمز تصادفی خودش را داشته باشد.
- احراز هویت دوعاملی را روشن کنید، از ایمیل و بانک شروع کنید؛ برنامه احراز هویت یا کلید امنیتی از کدهای پیامکی بهتر است.
- هر جا سایتی پشتیبانی میکند به passkey روی بیاورید. دیگر رمزی برای نشت یا تکرار باقی نمیماند.
- ایمیل خود را در Have I Been Pwned بررسی کنید و هر رمزی را که تکرار کردهاید عوض کنید.
- به هشدارهای «ورود تازه» که خودتان انجام ندادهاید واکنش نشان دهید: رمز را عوض کنید و از نشستهای دیگر خارج شوید.
- از ورود از طریق شبکههای ناشناس پرهیز کنید. پروکسی رایگانی که یک غریبه اداره میکند میتواند ترافیک شما را بخواند؛ نوشته آیا پروکسیهای رایگان امن هستند؟ را ببینید.
این موضوع کجا بیشترین اهمیت را دارد
- فروشگاههای اینترنتی و بازارگاهها. کارتهای ذخیرهشده، کارتهای هدیه و امتیازهای وفاداری حسابها را ارزشمند میکنند؛ در صفحه تجارت الکترونیک ما ببینید فروشگاهها ویترین خود را چگونه میآزمایند.
- بانکها و فینتک. تصاحب حساب مستقیم به جابهجایی پول میرسد؛ صفحه مالی توضیح میدهد تیمهای مالی صفحههای عمومی خود را چگونه از منطقههای دیگر بررسی میکنند.
- پخش ویدیو و بازی. حسابهای اشتراکی و دوبارهفروختهشده بازاری همیشگی برای اطلاعات ورود دزدیدهشدهاند.
- هر سایتی که داده شخصی گردآوری میکند. تصاحب حساب اطلاعات ذخیرهشده کاربر را افشا میکند که افزون بر کلاهبرداری، مسئله حفاظت از داده هم هست؛ نوشته دادههای شخصی در مجموعهدادههای اسکرپشده جنبه مدیریت آن را برای تیمهای داده پوشش میدهد.
خطاهای رایج
- تکیه بر مسدودسازی IP. در برابر حملههای پخششده شکست میخورد.
- قفل کردن حساب پس از چند شکست. به مهاجمان اجازه میدهد مشتریان شما را بیرون بگذارند.
- پیام خطای متفاوت برای «رمز نادرست» و «حساب وجود ندارد». فرم ورود شما را به ابزار رایگان بررسی ایمیل تبدیل میکند.
- محافظت از فرم وب و غفلت از API. برنامههای موبایل و نسخههای قدیمی API اغلب endpoint ورود خود را با محدودیتهای ضعیفتر دارند.
- اجبار به تغییر دورهای رمز. NIST SP 800-63B میگوید این کار را نکنید؛ تغییر رمز را فقط وقتی نشانهای از به خطر افتادن هست اجباری کنید.
- زیر نظر گرفتن فقط لحظه ورود. تصاحب حساب بیش از همه در آنچه پس از ورود رخ میدهد دیده میشود.
راهنمای انتخاب
| وضعیت شما | نخستین کار |
|---|---|
| ورودهای ناموفق جهش کردهاند و بیشتر نامهای کاربری ناشناساند | آن را credential stuffing در نظر بگیرید: اصطکاک را برای نشستهای پرخطر بالا ببرید و برای ورودهای موفق از دستگاه تازه عامل دوم بخواهید |
| سایت کوچکی بدون تیم امنیتی دارید | MFA، بررسی رمزهای نشتکرده هنگام ثبتنام و تغییر رمز و یک سرویس مدیریتشده حفاظت در برابر بات جلوی صفحه ورود اضافه کنید |
| حسابهای مدیر یا کارکنان فقط رمز عبور دارند | همین حالا MFA یا passkey را برای آنها الزامی کنید |
| مشتریان از ورودهایی خبر میدهند که انجام ندادهاند | بازنشانی رمز را برای حسابهای آسیبدیده اجباری کنید، به آنها خبر دهید و بررسی کنید پس از ورود چه چیزی تغییر کرده است |
| امروز فقط IP مسدود میکنید | آن را بهعنوان یک سیگنال نگه دارید؛ محدودیت برای هر حساب و هر endpoint و بررسی دستگاه را اضافه کنید |
| کاربری هستید که رمزها را تکرار میکند | به مدیر رمز عبور روی بیاورید و احراز هویت دوعاملی را از ایمیل شروع کنید |
پرسشهای متداول
آیا credential stuffing غیرقانونی است؟
بله. ورود به حساب شخص دیگر بدون اجازه، طبق قوانین جرایم رایانهای بیشتر کشورها دسترسی غیرمجاز است، هر ابزاری که به کار رود. آزمودن فقط روی سامانههایی قانونی است که مال شماست یا برای آزمودنشان اجازه کتبی دارید.
تفاوت credential stuffing با نشت داده چیست؟
نشت داده، دزدیدن داده از یک سرویس است. credential stuffing چیزی است که پس از آن رخ میدهد، وقتی جفتهای دزدیدهشده روی سرویسهای دیگر امتحان میشوند. سایتی که زیر حمله است ممکن است خودش هرگز دچار نشت نشده باشد.
آیا CAPTCHA جلوی credential stuffing را میگیرد؟
آن را کُند و پرهزینهتر میکند، اما دفاع کاملی نیست. OWASP آن را یکی از چند لایه و پس از احراز هویت چندعاملی میآورد.
چرا حساب را پس از سه رمز نادرست قفل نکنیم؟
در credential stuffing هر حساب معمولاً فقط یک تلاش میبیند، پس قفل بهندرت فعال میشود. جایی هم که فعال شود، میتوان از آن برای بیرون گذاشتن کاربران واقعی استفاده کرد. محدودیتهایی که میان حساب، دستگاه و endpoint پخش شدهاند بهتر کار میکنند.
آیا بررسی رمزها با Pwned Passwords برای کاربرانم امن است؟
با API بازهها فقط پنج نویسه نخست هش SHA-1 رمز را میفرستید و مقایسه روی سرور خودتان انجام میشود. سرویس هرگز رمز کامل یا هش کامل آن را نمیبیند.
آیا passkeyها به credential stuffing پایان میدهند؟
برای حسابهایی که فقط با passkey وارد میشوند، بله: هیچ رمز تکرارشدنی برای امتحان کردن وجود ندارد. تا وقتی سایتی هنوز رمز عبور را بهعنوان راه جایگزین میپذیرد، آن راه جایگزین هم به همان حفاظتها نیاز دارد.
خلاصه
credential stuffing نشت یک سایت را به تصاحب حساب در سایتهای بسیار تبدیل میکند، چون مردم رمزها را تکرار میکنند. این حمله میان نشانیهای IP بسیار پخش میشود، پس مسدودسازی IP بهتنهایی جلوی آن را نمیگیرد. دفاعهای کارساز اینها هستند: احراز هویت چندعاملی یا passkey، رد کردن رمزهایی که در فهرستهای نشت آمدهاند چنانکه NIST SP 800-63B الزام میکند، محدودیت تلاش وابسته به حساب و دستگاه، تشخیص بات و زیر نظر گرفتن آنچه پس از ورود رخ میدهد. کاربران با مدیر رمز عبور و رمزهای یکتا در را از سمت خود میبندند. برای آزمودن مشروع روندهای ورود و صفحههای خودتان از منطقههای دیگر، خدمات پروکسی و پروکسی مسکونی ما را ببینید.




