از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
ساخت یک اسکنر امنیتی ساده برنامه وب با پایتون: راهنمای مبتدیان
سرفصلهای مطلب
در این مقاله، شما می خواهید یاد بگیرید که یک ابزار امنیتی اساسی ایجاد کنید که می تواند در شناسایی آسیب پذیری های رایج در برنامه های وب مفید باشد.
من اینجا دو هدف دارم. اولین مورد این است که شما را با مهارت هایی برای توسعه ابزارهایی که می توانند به بهبود وضعیت امنیتی کلی وب سایت شما کمک کنند، توانمند کنیم. دوم کمک به تمرین برنامه نویسی پایتون است.
در این راهنما، شما یک اسکنر امنیتی مبتنی بر پایتون خواهید ساخت که می تواند XSS، تزریق SQL و PII حساس (اطلاعات شناسایی شخصی) را تشخیص دهد.
انواع آسیب پذیری ها
به طور کلی، میتوانیم آسیبپذیریهای امنیتی وب را در سطلهای زیر دستهبندی کنیم (برای سطلهای بیشتر، ۱۰ OWASP برتر را بررسی کنید):
-
تزریق SQL: تکنیکی که در آن مهاجمان میتوانند کد SQL مخرب را از طریق ورودیهای نامعتبر در جستوجوهای SQL وارد کنند و به آنها اجازه تغییر/خواندن محتوای پایگاه داده را میدهند.
-
اسکریپت بین سایتی (XSS): تکنیکی که در آن مهاجمان جاوا اسکریپت مخرب را در وب سایت های قابل اعتماد تزریق می کنند. این به آنها اجازه می دهد تا کد جاوا اسکریپت را در زمینه مرورگر اجرا کنند و اطلاعات حساس را بدزدند یا عملیات غیرمجاز را انجام دهند.
-
قرار گرفتن در معرض اطلاعات حساس: یک مشکل امنیتی که در آن یک برنامه به طور ناخواسته داده های حساسی مانند رمزهای عبور، کلیدهای API و غیره را نشان می دهد روی از طریق گزارشها، ذخیرهسازی ناامن و سایر آسیبپذیریها.
-
تنظیمات اشتباه امنیتی رایج: مشکلات امنیتی که به دلیل پیکربندی نادرست سرورهای وب رخ می دهد – مانند اعتبار پیش فرض برای حساب های سرپرست، حالت اشکال زدایی فعال، داشبوردهای سرپرست در دسترس عموم با اعتبار ضعیف و غیره روی.
-
ضعف های اساسی احراز هویت: مشکلات امنیتی که به دلیل نقص در سیاست های رمز عبور، فرآیندهای احراز هویت کاربر، مدیریت نادرست جلسه و غیره رخ می دهد. روی.
فهرست مطالب
-
پیش نیازها
-
راه اندازی محیط توسعه ما
-
ساختن کلاس اسکنر هسته ما
-
پیاده سازی خزنده
-
طراحی و اجرای بررسی های امنیتی
-
بررسی تشخیص تزریق SQL
-
XSS (Cross-Site Scripting) را بررسی کنید
-
بررسی قرار گرفتن در معرض اطلاعات حساس
-
-
پیاده سازی منطق اصلی اسکن
-
گسترش اسکنر امنیتی
-
بسته بندی
پیش نیازها
برای دنبال کردن این آموزش، شما نیاز دارید:
-
پایتون 3.x
-
درک اولیه پروتکل های HTTP
-
درک اولیه از برنامه های کاربردی وب
-
درک اولیه از روش عملکرد XSS، تزریق SQL و حملات امنیتی اساسی
راه اندازی محیط توسعه ما
بیایید وابستگی های مورد نیاز خود را با دستور زیر نصب کنیم:
pip install requests beautifulsoup4 urllib3 colorama
ما از این وابستگی ها در فایل کد خود استفاده خواهیم کرد:
# Required packages
import requests
from bs4 import BeautifulSoup
import urllib.parse
import colorama
import re
from concurrent.futures import ThreadPoolExecutor
import sys
from typing import List, Dict, Set
ساختن کلاس اسکنر هسته ما
هنگامی که وابستگی ها را دارید، نوبت به نوشتن کلاس اسکنر اصلی می رسد.
این کلاس به عنوان کلاس اصلی ما عمل می کند که عملکرد اسکن امنیت وب را مدیریت می کند. صفحات بازدید شده ما را ردیابی می کند و یافته های ما را نیز ذخیره می کند.
ما داریم normalize_url
عملکردی که ما از آن برای اطمینان از عدم اسکن مجدد URL هایی که قبلاً دیده شده اند استفاده می کنیم. این تابع اساساً پارامترهای HTTP GET را از URL حذف می کند. به عنوان مثال، https://example.com/page؟id=1
تبدیل خواهد شد https://example.com/page
پس از عادی سازی آن
class WebSecurityScanner:
def __init__(self, target_url: str, max_depth: int = 3):
"""
Initialize the security scanner with a target URL and maximum crawl depth.
Args:
target_url: The base URL to scan
max_depth: Maximum depth for crawling links (default: 3)
"""
self.target_url = target_url
self.max_depth = max_depth
self.visited_urls: Set[str] = set()
self.vulnerabilities: List[Dict] = []
self.session = requests.Session()
# Initialize colorama for cross-platform colored output
colorama.init()
def normalize_url(self, url: str) -> str:
"""Normalize the URL to prevent duplicate checks"""
parsed = urllib.parse.urlparse(url)
return f"{parsed.scheme}://{parsed.netloc}{parsed.path}"
پیاده سازی خزنده
اولین قدم در اسکنر ما پیاده سازی یک خزنده وب است که صفحات و URL ها را در یک برنامه هدف مشخص کشف می کند. مطمئن شوید که این توابع را در ما می نویسید WebSecurityScanner
کلاس
def crawl(self, url: str, depth: int = 0) -> None:
"""
Crawl the website to discover pages and endpoints.
Args:
url: Current URL to crawl
depth: Current depth in the crawl tree
"""
if depth > self.max_depth or url in self.visited_urls:
return
try:
self.visited_urls.add(url)
response = self.session.get(url, verify=False)
soup = BeautifulSoup(response.text, 'html.parser')
# Find all links in the page
links = soup.find_all('a', href=True)
for link in links:
next_url = urllib.parse.urljoin(url, link['href'])
if next_url.startswith(self.target_url):
self.crawl(next_url, depth + 1)
except Exception as e:
print(f"Error crawling {url}: {str(e)}")
این crawl
تابع به ما کمک می کند تا یک خزیدن در عمق یک وب سایت را انجام دهیم. در حالی که در دامنه مشخص شده باقی می ماند، تمام صفحات یک وب سایت را کاوش می کند.
برای مثال، اگر قصد دارید از این اسکنر استفاده کنید روی https://google.com
، ابتدا این تابع همه URL ها را دریافت می کند و سپس یک به یک بررسی می کند که آیا آنها به دامنه مشخص شده تعلق دارند (یعنی google.com
). اگر چنین است، به صورت بازگشتی به اسکن URL دیده شده تا عمق مشخصی که با depth
پارامتر به عنوان آرگومان تابع. ما همچنین برای اطمینان از رسیدگی به خطاها و گزارش هر گونه خطا در حین خزیدن، برخی از مدیریت استثنا داریم.
طراحی و اجرای بررسی های امنیتی
حالا بیایید در نهایت به قسمت آبدار برسیم و بررسی های امنیتی خود را اجرا کنیم. ابتدا با SQL Injection شروع می کنیم.
بررسی تشخیص تزریق SQL
def check_sql_injection(self, url: str) -> None:
"""Test for potential SQL injection vulnerabilities"""
sql_payloads = ["'", "1' OR '1'='1", "' OR 1=1--", "' UNION SELECT NULL--"]
for payload in sql_payloads:
try:
# Test GET parameters
parsed = urllib.parse.urlparse(url)
params = urllib.parse.parse_qs(parsed.query)
for param in params:
test_url = url.replace(f"{param}={params[param][0]}",
f"{param}={payload}")
response = self.session.get(test_url)
# Look for SQL error messages
if any(error in response.text.lower() for error in
['sql', 'mysql', 'sqlite', 'postgresql', 'oracle']):
self.report_vulnerability({
'type': 'SQL Injection',
'url': url,
'parameter': param,
'payload': payload
})
except Exception as e:
print(f"Error testing SQL injection روی {url}: {str(e)}")
این تابع اساساً با آزمایش URL در برابر بارهای متداول تزریق SQL و جستجوی پیام های خطایی که ممکن است به آسیب پذیری امنیتی اشاره کند، بررسی های اولیه تزریق SQL را انجام می دهد.
بر اساس روی پیام خطای دریافت شده پس از انجام یک درخواست ساده GET روی URL، بررسی می کنیم که آیا آن پیام یک خطای پایگاه داده است یا خیر. اگر اینطور است، از آن استفاده می کنیم report_vulnerability
عملکردی برای گزارش آن به عنوان یک مشکل امنیتی در گزارش نهایی ما که این اسکریپت ایجاد خواهد کرد. به خاطر این مثال، ما چند بار تزریق SQL را که معمولاً آزمایش میشوند انتخاب میکنیم، اما میتوانید این را برای آزمایش بیشتر گسترش دهید.
XSS (Cross-Site Scripting) را بررسی کنید
حالا بیایید دومین بررسی امنیتی را برای بارهای XSS پیاده سازی کنیم.
def check_xss(self, url: str) -> None:
"""Test for potential Cross-Site Scripting vulnerabilities"""
xss_payloads = [
"<script>alert('XSS')</script>",
"<img src=x onerror=alert('XSS')>",
"javascript:alert('XSS')"
]
for payload in xss_payloads:
try:
# Test GET parameters
parsed = urllib.parse.urlparse(url)
params = urllib.parse.parse_qs(parsed.query)
for param in params:
test_url = url.replace(f"{param}={params[param][0]}",
f"{param}={urllib.parse.quote(payload)}")
response = self.session.get(test_url)
if payload in response.text:
self.report_vulnerability({
'type': 'Cross-Site Scripting (XSS)',
'url': url,
'parameter': param,
'payload': payload
})
except Exception as e:
print(f"Error testing XSS روی {url}: {str(e)}")
این تابع، درست مانند تستر تزریق SQL، از مجموعه ای از بارهای متداول XSS استفاده می کند و همان ایده را اعمال می کند. اما تفاوت اصلی در اینجا این است که ما بهجای جستجوی پیغام خطا به دنبال این هستیم که بار تزریقیمان در پاسخ ما بدون تغییر ظاهر شود.
اگر بتوانید بار تزریق شده ما را ببینید، به احتمال زیاد در زمینه مرورگر قربانی به عنوان یک حمله XSS منعکس شده اجرا می شود.
بررسی قرار گرفتن در معرض اطلاعات حساس
حالا بیایید بررسی نهایی خود را برای PII حساس اجرا کنیم.
def check_sensitive_info(self, url: str) -> None:
"""Check for exposed sensitive information"""
sensitive_patterns = {
'email': r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
'phone': r'\b\d{3}[-.]?\d{3}[-.]?\d{4}\b',
'ssn': r'\b\d{3}-\d{2}-\d{4}\b',
'api_key': r'api[_-]?key[_-]?([\'"|`])([a-zA-Z0-9]{32,45})\1'
}
try:
response = self.session.get(url)
for info_type, pattern in sensitive_patterns.items():
matches = re.finditer(pattern, response.text)
for match in matches:
self.report_vulnerability({
'type': 'Sensitive Information Exposure',
'url': url,
'info_type': info_type,
'pattern': pattern
})
except Exception as e:
print(f"Error checking sensitive information روی {url}: {str(e)}")
این تابع از مجموعه ای از الگوهای Regex از پیش تعریف شده برای جستجوی PII مانند ایمیل، شماره تلفن، SSN و کلیدهای API (که با api-key-
درست مانند دو تابع قبلی، ما از متن پاسخ برای URL و الگوهای Regex خود برای یافتن این PII ها در متن پاسخ استفاده می کنیم. اگر موردی پیدا کردیم، آنها را با report_vulnerability
تابع مطمئن شوید که همه این توابع در آن تعریف شده اند WebSecurityScanner
کلاس
پیاده سازی منطق اصلی اسکن
بیایید در نهایت همه چیز را با تعریف کردن به هم بچسبانیم scan
و report_vulnerability
عملکرد در WebSecurityScanner
کلاس:
def scan(self) -> List[Dict]:
"""
Main scanning method that coordinates the security checks
Returns:
List of discovered vulnerabilities
"""
print(f"\n{colorama.Fore.BLUE}Starting security scan of {self.target_url}{colorama.Style.RESET_ALL}\n")
# First, crawl the website
self.crawl(self.target_url)
# Then run security checks روی all discovered URLs
with ThreadPoolExecutor(max_workers=5) as executor:
for url in self.visited_urls:
executor.submit(self.check_sql_injection, url)
executor.submit(self.check_xss, url)
executor.submit(self.check_sensitive_info, url)
return self.vulnerabilities
def report_vulnerability(self, vulnerability: Dict) -> None:
"""Record and display found vulnerabilities"""
self.vulnerabilities.append(vulnerability)
print(f"{colorama.Fore.RED}[VULNERABILITY FOUND]{colorama.Style.RESET_ALL}")
for key, value in vulnerability.items():
print(f"{key}: {value}")
print()
این کد ما را تعریف می کند scan
تابعی که اساساً آن را فراخوانی می کند crawl
کار کرده و به صورت بازگشتی شروع به خزیدن در وب سایت کنید. با multithreading، هر سه بررسی امنیتی را اعمال خواهیم کرد روی URL های بازدید شده
ما نیز تعریف کرده ایم report_vulnerability
عملکردی که به طور موثر خواهد بود print آسیب پذیری ما در برابر console و همچنین آنها را در ما ذخیره کنید vulnerabilities
آرایه
حالا بیایید در نهایت از اسکنر خود با ذخیره آن به عنوان استفاده کنیم scanner.py
:
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python scanner.py <target_url>")
sys.exit(1)
target_url = sys.argv[1]
scanner = WebSecurityScanner(target_url)
vulnerabilities = scanner.scan()
# Print summary
print(f"\n{colorama.Fore.GREEN}Scan Complete!{colorama.Style.RESET_ALL}")
print(f"Total URLs scanned: {len(scanner.visited_urls)}")
print(f"Vulnerabilities found: {len(vulnerabilities)}")
URL هدف به عنوان یک آرگومان سیستم ارائه می شود و ما خلاصه ای از URL های اسکن شده و آسیب پذیری های یافت شده را در پایان اسکن خود دریافت می کنیم. اکنون بیایید در مورد چگونگی گسترش اسکنر و افزودن ویژگی های بیشتر بحث کنیم.
گسترش اسکنر امنیتی
در اینجا چند ایده برای گسترش این اسکنر امنیتی اساسی به چیزی حتی پیشرفته تر وجود دارد:
-
بررسیهای آسیبپذیری بیشتری مانند تشخیص CSRF، پیمایش دایرکتوری و غیره اضافه کنید روی.
-
بهبود گزارش با خروجی HTML یا PDF.
-
گزینه های پیکربندی را برای شدت اسکن و دامنه جستجو اضافه کنید (تعیین عمق اسکن ها از طریق آرگومان CLI).
-
اجرای محدود کردن نرخ مناسب
-
افزودن پشتیبانی احراز هویت برای آزمایش URL هایی که نیاز به احراز هویت مبتنی بر جلسه دارند.
بسته بندی
اکنون می دانید که چگونه یک اسکنر امنیتی اولیه بسازید! این اسکنر چند مفهوم اصلی امنیت وب را نشان می دهد.
به خاطر داشته باشید که این آموزش فقط باید برای اهداف آموزشی استفاده شود. چندین برنامه کاربردی حرفه ای در سطح سازمانی مانند Burp Suite و OWASP Zap وجود دارد که می توانند صدها آسیب پذیری امنیتی را در مقیاسی بسیار بزرگتر بررسی کنند.
امیدوارم اصول اولیه امنیت وب و کمی برنامه نویسی پایتون را نیز یاد گرفته باشید.
منتشر شده در 1403-12-12 23:44:14