تجزئة SHA-256 بـ Python — دليل hashlib وأمثلة
استخدم مولد Hash SHA-256 المجاني مباشرةً في متصفحك — لا حاجة للتثبيت.
جرّب مولد Hash SHA-256 أونلاين ←كل خط أنابيب نشر بنيته احتاج في نهاية المطاف إلى التحقق من مجموع اختباري لملف، أو توقيع حمولة webhook، أو بصمة مفتاح ذاكرة تخزين مؤقت. تجزئة SHA-256 بـ Python مع الوحدة المدمجة hashlib يتعامل مع كل هذه الحالات — وهو مثبّت لديك بالفعل. hashlib.sha256() يُغلّف تنفيذ OpenSSL على CPython، فهو سريع ومتوافق مع FIPS افتراضياً. للحصول على تجزئة سريعة دون كتابة أي كود، يعطيك مولّد SHA-256 الأونلاين النتيجة فوراً. جميع الأمثلة تستهدف Python 3.9+.
- ✓hashlib.sha256(data).hexdigest() هي الطريقة المعيارية لتجزئة البايتات — جزء من stdlib ومدعومة بـ OpenSSL.
- ✓يجب تشفير النصوص إلى بايتات أولاً: hashlib.sha256("text".encode("utf-8")).
- ✓للمجاميع الاختبارية للملفات، أدخل البيانات في أجزاء عبر .update() — لا تحمّل ملفاً كبيراً في الذاكرة دفعةً واحدة.
- ✓يتطلب HMAC-SHA256 وحدة hmac: hmac.new(key, msg, hashlib.sha256) — SHA-256 وحده لا يدعم المفاتيح.
ما هي تجزئة SHA-256؟
يأخذ SHA-256 (خوارزمية التجزئة الآمنة، 256 بت) مدخلاً ذا طول اعتباطي وينتج ملخصاً ثابتاً بحجم 256 بت (32 بايت). المدخل ذاته ينتج دائماً المخرج ذاته، لكن حتى تغيير بت واحد في المدخل ينتج تجزئة مختلفة كلياً — وهذه الخاصية تُسمى تأثير الانهيار. SHA-256 جزء من عائلة SHA-2، معيار من NIST، وهو العمود الفقري لبصمات شهادات TLS ومعرّفات الإيداعات في Git وترويسات كتل Bitcoin والتحقق من سلامة الملفات. تستخدم الخوارزمية بنية Merkle-Damgård مع 64 جولة ضغط لإنتاج مخرجاتها البالغة 256 بت.
a1f7c3d8e9b2...27ae41e4649b (64 حرفاً سداسياً)
deployment-v4.2.1
الملخص السداسي أعلاه هو التمثيل المعياري — 64 حرفاً سداسياً عشرياً، دائماً بالطول ذاته سواء جزّأت بايتاً واحداً أو صورة قرص كاملة.
hashlib.sha256() — أسلوب المكتبة القياسية
وحدة hashlib مدمجة في Python من الأساس — لا حاجة لـ pip install. استدعِ hashlib.sha256() مع وسيطة bytes لإنشاء كائن تجزئة، ثم احصل على النتيجة عبر .hexdigest() (سلسلة سداسية) أو .digest() (بايتات خام). اسم الدالة بأحرف صغيرة: sha256، وليس SHA256.
import hashlib # تجزئة سلسلة بايتات مباشرةً digest = hashlib.sha256(b"deployment-v4.2.1").hexdigest() print(digest) # a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
أكثر خطأ شائع مع hashlib.sha256() هو تمرير str بدلاً من bytes. نصوص Python هي Unicode، وتعمل دوال التجزئة على بايتات خام. يجب استدعاء .encode("utf-8") قبل التجزئة. يقع في هذا الخطأ كل مبتدئ تقريباً.
import hashlib
# يجب تشفير النصوص إلى بايتات قبل التجزئة
config_key = "redis://cache.internal:6379/0"
digest = hashlib.sha256(config_key.encode("utf-8")).hexdigest()
print(digest)
# 7d3f8c2a1b9e4f5d6c8a7b3e2f1d9c4a5b8e7f6d3c2a1b9e4f5d6c8a7b3e2f1dتتيح لك دالة .update() إدخال البيانات تدريجياً. استدعاء h.update(a); h.update(b) يعادل hashlib.sha256(a + b). هكذا تجزّئ الملفات في أجزاء دون تحميل المحتوى بأكمله في الذاكرة.
import hashlib h = hashlib.sha256() h.update(b"request_id=req_7f3a91bc") h.update(b"×tamp=1741614120") h.update(b"&amount=4999") print(h.hexdigest()) # يعادل hashlib.sha256(b"request_id=req_7f3a91bc×tamp=1741614120&amount=4999").hexdigest()
.digest() تُعيد 32 بايتاً خاماً. .hexdigest() تُعيد سلسلة سداسية من 64 حرفاً. استخدم .digest() عند تغذية النتيجة في HMAC أو ترميز Base64 أو البروتوكولات الثنائية. استخدم .hexdigest() للتسجيل وأعمدة قاعدة البيانات ومقارنة المجاميع الاختبارية.HMAC-SHA256 — التجزئة بمفتاح مع وحدة hmac
لا يتعامل SHA-256 وحده مع المفاتيح السرية — أي شخص لديه المدخل ذاته يمكنه حساب التجزئة ذاتها. إذا أردت إثبات أن رسالة جاءت من مرسل محدد (التحقق من webhook، توقيع طلبات API، مصادقة الرموز)، تحتاج إلى HMAC. وحدة hmac جزء من المكتبة القياسية لـ Python وتدمج المفتاح في عملية التجزئة بحيث لا يمكن لأحد إنتاج هذا الملخص أو التحقق منه إلا من يملك المفتاح.
import hmac
import hashlib
# التحقق من توقيع webhook
secret_key = b"whsec_9f3a7b2e1d4c8a5b"
payload = b'{"event":"invoice.paid","invoice_id":"inv_8d2c","amount":14900}'
signature = hmac.new(secret_key, payload, hashlib.sha256).hexdigest()
print(signature)
# ملخص HMAC-SHA256 سداسي من 64 حرفاًيستلزم التحقق من HMAC الوارد استخدام hmac.compare_digest() بدلاً من العامل ==. عامل المساواة عرضة لهجمات التوقيت — يتوقف عند أول بايت مختلف، ويمكن للمهاجم قياس أوقات الاستجابة لتخمين التوقيع الصحيح بايتاً بايتاً. compare_digest() يعمل في وقت ثابت بغض النظر عن موضع الاختلاف.
import hmac
import hashlib
def verify_webhook(payload: bytes, received_sig: str, secret: bytes) -> bool:
"""التحقق من توقيع webhook باستخدام المقارنة في وقت ثابت."""
expected = hmac.new(secret, payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, received_sig)
# محاكاة التحقق من webhook بأسلوب Stripe
incoming_payload = b'{"event":"payment.completed","amount":4999}'
incoming_signature = "a1b2c3d4e5f6..." # من ترويسة X-Signature
webhook_secret = b"whsec_9f3a7b2e1d4c"
if verify_webhook(incoming_payload, incoming_signature, webhook_secret):
print("التوقيع صالح — معالجة الحدث")
else:
print("عدم تطابق التوقيع — رفض الطلب")توقيع طلبات API بـ HMAC-SHA256
يتبع توقيع طلبات API المبدأ ذاته: أنشئ سلسلة متعارفاً عليها من مكونات الطلب (الطريقة، المسار، الطابع الزمني، تجزئة الجسم) ثم وقّعها بمفتاحك السري. AWS Signature V4 وStripe وـGitHub webhooks كلها تستخدم أشكالاً من هذا النمط.
import hmac
import hashlib
import time
def sign_request(method: str, path: str, body: bytes, secret: bytes) -> str:
"""إنشاء توقيع HMAC-SHA256 لطلب API."""
timestamp = str(int(time.time()))
body_hash = hashlib.sha256(body).hexdigest()
# السلسلة المتعارف عليها: الطريقة + المسار + الطابع الزمني + تجزئة الجسم
canonical = f"{method}\n{path}\n{timestamp}\n{body_hash}"
signature = hmac.new(secret, canonical.encode("utf-8"), hashlib.sha256).hexdigest()
return f"ts={timestamp},sig={signature}"
# الاستخدام
api_secret = b"sk_live_9f3a7b2e1d4c8a5b6e7f"
request_body = b'{"customer_id":"cust_4f2a","plan":"enterprise"}'
auth_header = sign_request("POST", "/api/v2/subscriptions", request_body, api_secret)
print(f"Authorization: HMAC-SHA256 {auth_header}")
# Authorization: HMAC-SHA256 ts=1741614120,sig=7d3f8c2a...HMAC-SHA256 مُشفَّر بـ Base64
تتوقع بعض واجهات API (AWS Signature V4 وبعض بوابات الدفع) نتيجة HMAC كسلسلة مشفّرة بـ Base64 بدلاً من السداسية. الفارق: السداسية تستخدم 64 حرفاً، بينما Base64 تستخدم 44 حرفاً للملخص ذاته بحجم 32 بايت.
import hmac
import hashlib
import base64
secret = b"webhook_secret_9f3a"
message = b"POST /api/v2/events 1741614120"
# مخرجات سداسية: 64 حرفاً
hex_sig = hmac.new(secret, message, hashlib.sha256).hexdigest()
print(f"Hex: {hex_sig}")
# مخرجات Base64: 44 حرفاً (أقصر، شائع في ترويسات HTTP)
raw_sig = hmac.new(secret, message, hashlib.sha256).digest()
b64_sig = base64.b64encode(raw_sig).decode("ascii")
print(f"Base64: {b64_sig}")تجزئة datetime وUUID والكائنات المخصصة
يعمل SHA-256 على بايتات خام، لذا يجب تسلسل الأنواع غير البايتية — datetime وUUID والـ dataclasses ونماذج Pydantic — إلى بايتات قبل التجزئة. لا يوجد تحويل تلقائي؛ أنت تختار التمثيل المتعارف عليه. للتجزئة الحتمية عبر الأنظمة، استخدم دائماً ترميزاً صريحاً وصيغة تسلسل ثابتة (ISO 8601 لـ datetime، الصيغة النصية المعيارية لـ UUID، JSON بمفاتيح مرتبة للقواميس).
import hashlib
import uuid
from datetime import datetime, timezone
# datetime — استخدم ISO 8601 مع إزاحة UTC الصريحة للتنقلية
event_time = datetime(2026, 3, 28, 12, 0, 0, tzinfo=timezone.utc)
time_hash = hashlib.sha256(event_time.isoformat().encode("utf-8")).hexdigest()
print(f"datetime hash: {time_hash[:16]}...")
# UUID — جزّئ الصيغة النصية المعيارية (أحرف صغيرة مع شرطات)
record_id = uuid.uuid4()
uuid_hash = hashlib.sha256(str(record_id).encode("utf-8")).hexdigest()
print(f"UUID hash: {uuid_hash[:16]}...")للكائنات المخصصة، سلسلها إلى تمثيل بايتات متعارف عليه قبل التجزئة. JSON بمفاتيح مرتبة يعمل جيداً للكائنات المشابهة للقواميس:
import hashlib
import json
from dataclasses import dataclass, asdict
@dataclass
class Event:
id: str
type: str
amount: int
timestamp: str
def hash_event(event: Event) -> str:
"""تجزئة كائن dataclass باستخدام JSON بمفاتيح مرتبة للحتمية."""
canonical = json.dumps(asdict(event), sort_keys=True, separators=(",", ":"))
return hashlib.sha256(canonical.encode("utf-8")).hexdigest()
e = Event(id="evt_4f2a", type="payment.completed", amount=4999, timestamp="2026-03-28T12:00:00Z")
print(hash_event(e)) # ثابت عبر التشغيلات والأجهزةsort_keys=True) عند تجزئة الكائنات المسلسلة بـ JSON. ترتيب الإدراج محفوظ في Python 3.7+ لكنه قد يختلف عبر مسارات التسلسل، مما ينتج تجزئات مختلفة لبيانات متطابقة.المجموع الاختباري SHA-256 للملفات — التحقق من التنزيلات والتصنيفات
حساب المجموع الاختباري SHA-256 لملف هو أحد أكثر استخدامات الخوارزمية شيوعاً. تجده في كل مكان: صفحات إصدار ثنائيات Go وملفات Python wheel وملفات بيان صور Docker وتحديثات البرامج الثابتة. المفتاح هو قراءة الملف في أجزاء بدلاً من تحميله دفعةً واحدة — صورة ISO بحجم 2 جيجابايت لا ينبغي أن تتطلب 2 جيجابايت من الذاكرة لمجرد تجزئتها.
import hashlib
def sha256_checksum(filepath: str, chunk_size: int = 8192) -> str:
"""احسب تجزئة SHA-256 لملف مع القراءة في أجزاء لتوفير الذاكرة."""
h = hashlib.sha256()
with open(filepath, "rb") as f:
for chunk in iter(lambda: f.read(chunk_size), b""):
h.update(chunk)
return h.hexdigest()
# تجزئة ملف إصدار
checksum = sha256_checksum("/tmp/release-v4.2.1.tar.gz")
print(f"SHA-256: {checksum}")أضاف Python 3.11 الدالة hashlib.file_digest() التي تجري القراءة المجزأة داخلياً وقد تستخدم تحسينات النسخ الصفري على المنصات المدعومة. إذا كنت على 3.11 أو أحدث، فضّلها على الحلقة اليدوية.
import hashlib
with open("/tmp/release-v4.2.1.tar.gz", "rb") as f:
digest = hashlib.file_digest(f, "sha256")
print(digest.hexdigest())التحقق من ملف محمّل مقابل مجموع اختباري معروف
import hashlib
import hmac as hmac_mod # لـ compare_digest فقط
def verify_checksum(filepath: str, expected_hex: str) -> bool:
"""التحقق من مجموع SHA-256 الاختباري باستخدام المقارنة في وقت ثابت."""
h = hashlib.sha256()
with open(filepath, "rb") as f:
for chunk in iter(lambda: f.read(8192), b""):
h.update(chunk)
return hmac_mod.compare_digest(h.hexdigest(), expected_hex.lower())
# التحقق من ملف إصدار
expected = "a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db"
if verify_checksum("/tmp/release-v4.2.1.tar.gz", expected):
print("المجموع الاختباري متطابق — الملف سليم")
else:
print("عدم تطابق المجموع الاختباري — قد يكون الملف تالفاً أو معدّلاً")hmac.compare_digest() لمقارنة المجاميع الاختبارية حتى حين لا يوجد مفتاح سري. المقارنة في وقت ثابت تمنع تسرب المعلومات عبر التوقيت. العامل == يعمل وظيفياً لكنه غير آمن للسياقات الأمنية الحساسة.SHA-256 مع ترميز Base64
تتوقع بعض البروتوكولات ملخص SHA-256 كسلسلة Base64 بدلاً من سداسية. ترويسات HTTP مثل Content-Digest وIntegrity (سلامة الموارد الفرعية في المتصفحات) تستخدم Base64، وتوقيعات JWT مُشفَّرة بـ Base64url. الحيلة هي ترميز بايتات .digest() الخام بـ Base64، وليس السلسلة السداسية.
import hashlib
import base64
data = b"integrity check payload"
# الصحيح: Base64 للبايتات الخام (32 بايت → 44 حرفاً بـ Base64)
raw_digest = hashlib.sha256(data).digest()
b64_digest = base64.b64encode(raw_digest).decode("ascii")
print(f"sha256-{b64_digest}")
# sha256-<44 حرفاً>
# الخطأ: Base64 للسلسلة السداسية (64 بايت ASCII → 88 حرفاً بـ Base64 — ضعف الحجم)
hex_digest = hashlib.sha256(data).hexdigest()
wrong = base64.b64encode(hex_digest.encode()).decode()
print(f"طول خاطئ: {len(wrong)} حرفاً") # 88 — ليس ما تتوقعه الـ APIs.digest() وليس .hexdigest() قبل ترميز Base64.مرجع hashlib.sha256()
الدالة البانية والدوال على كائن تجزئة SHA-256:
معاملات hmac.new() للتجزئة بمفتاح:
مكتبة cryptography — واجهة برمجية بديلة لـ SHA-256
توفر حزمة cryptography واجهة برمجية مختلفة لـ SHA-256 عبر primitives الـ hazmat. نادراً ما ألجأ إليها حين أحتاج فقط إلى تجزئة — hashlib أبسط ولا تعتمد على مكتبات خارجية. لكن إذا كان مشروعك يعتمد أصلاً على cryptography لـ TLS أو X.509 أو التشفير المتماثل، فاستخدام واجهة التجزئة الخاصة بها يُبقي كل شيء تحت مكتبة واحدة ويمنحك معالجة أخطاء متسقة.
from cryptography.hazmat.primitives import hashes from cryptography.hazmat.backends import default_backend digest = hashes.Hash(hashes.SHA256(), backend=default_backend()) digest.update(b"deployment-v4.2.1") result = digest.finalize() # 32 بايتاً خاماً print(result.hex()) # سلسلة سداسية من 64 حرفاً # a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
cryptography pip install cryptography. كائن التجزئة لاستخدام واحد: استدعاء .finalize() مرة ثانية يُثير AlreadyFinalized. استخدم .copy() قبل الإنهاء إذا أردت تفريع حالة التجزئة.تجزئة البيانات من ملف وطلب API
سيناريوان يظهران باستمرار: تجزئة ملف على القرص للتحقق من ملف إصدار، وتجزئة جسم طلب HTTP لاستخدامه مفتاح تخزين مؤقت أو التحقق من webhook.
قراءة الملف → حساب SHA-256 → المقارنة
import hashlib
import sys
def hash_file_safe(filepath: str) -> str | None:
"""تجزئة ملف مع معالجة صحيحة للأخطاء."""
try:
h = hashlib.sha256()
with open(filepath, "rb") as f:
for chunk in iter(lambda: f.read(16384), b""):
h.update(chunk)
return h.hexdigest()
except FileNotFoundError:
print(f"خطأ: {filepath} غير موجود", file=sys.stderr)
return None
except PermissionError:
print(f"خطأ: لا يوجد إذن قراءة لـ {filepath}", file=sys.stderr)
return None
result = hash_file_safe("/etc/nginx/nginx.conf")
if result:
print(f"SHA-256: {result}")طلب HTTP → تجزئة الجسم كمفتاح تخزين مؤقت
import hashlib
import urllib.request
import json
def fetch_and_hash(url: str) -> tuple[dict, str]:
"""جلب JSON من API وإرجاع البيانات مع تجزئة SHA-256 الخاصة بها."""
try:
with urllib.request.urlopen(url, timeout=10) as resp:
body = resp.read()
content_hash = hashlib.sha256(body).hexdigest()
data = json.loads(body)
return data, content_hash
except urllib.error.URLError as exc:
raise ConnectionError(f"فشل الجلب من {url}: {exc}") from exc
# مفتاح تخزين مؤقت بناءً على محتوى الاستجابة
data, digest = fetch_and_hash("https://api.exchange.internal/v2/rates")
print(f"تجزئة الاستجابة: {digest[:16]}...")
print(f"EUR/USD: {data.get('rates', {}).get('EUR', 'N/A')}")للتحقق السريع من مرة واحدة، مولّد SHA-256 من ToolDeck يعمل كلياً في متصفحك — دون الحاجة إلى كود.
تجزئة SHA-256 من سطر الأوامر
أحياناً تحتاج فقط إلى تجزئة سريعة في الطرفية خلال حادثة أو نشر. وحدة hashlib في Python لا تملك أمر فرعي لسطر الأوامر مدمجاً (بخلاف python3 -m json.tool)، لكن يمكنك استخدام سطر واحد أو أدوات النظام.
# سطر Python واحد echo -n "deployment-v4.2.1" | python3 -c "import hashlib,sys; print(hashlib.sha256(sys.stdin.buffer.read()).hexdigest())" # macOS / BSD echo -n "deployment-v4.2.1" | shasum -a 256 # Linux (coreutils) echo -n "deployment-v4.2.1" | sha256sum # OpenSSL (متعدد المنصات) echo -n "deployment-v4.2.1" | openssl dgst -sha256
# تجزئة ملف إصدار مضغوط sha256sum release-v4.2.1.tar.gz # أو openssl dgst -sha256 release-v4.2.1.tar.gz # التحقق مقابل مجموع اختباري معروف echo "a8f5f167f44f4964e6c998dee827110c release-v4.2.1.tar.gz" | sha256sum -c - # release-v4.2.1.tar.gz: OK
echo -n (بدون سطر جديد في النهاية) عند تجزئة النصوص من سطر الأوامر. أمر echo العادي يُضيف \n مما يغير التجزئة. هذا السبب الأول الذي يجعل الناس يحصلون على تجزئات مختلفة بين Python والصدفة.البديل عالي الأداء — hashlib مع OpenSSL وpycryptodome
على CPython، hashlib.sha256() يُفوّض بالفعل إلى تنفيذ OpenSSL بلغة C، فهو سريع — عادةً 500+ ميجابايت/ثانية على الأجهزة الحديثة.
إذا ظهرت تجزئة SHA-256 في مُحلّل الأداء — مثلاً عند حساب المجاميع الاختبارية لآلاف الملفات في خط أنابيب CI أو تجزئة كل جسم طلب في بوابة API عالية الإنتاجية — يوجد خياران: تحسين نمط استدعاء hashlib، أو التحول إلى pycryptodome للحصول على واجهة برمجية موحدة للتشفير تشمل SHA-3 وBLAKE2:
pip install pycryptodome
from Crypto.Hash import SHA256 h = SHA256.new() h.update(b"deployment-v4.2.1") print(h.hexdigest()) # a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
للتجزئة المتوازية للملفات عالية الإنتاجية، تأتي المكاسب الأكبر من تقليل overhead بايثون عبر أجزاء أكبر وتعدد الخيوط:
import hashlib
import os
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
def hash_file(path: Path) -> tuple[str, str]:
"""تجزئة ملف واحد وإرجاع (المسار، الملخص السداسي)."""
h = hashlib.sha256()
with open(path, "rb") as f:
for chunk in iter(lambda: f.read(65536), b""): # أجزاء 64 كيلوبايت
h.update(chunk)
return str(path), h.hexdigest()
def hash_directory(directory: str, pattern: str = "*.tar.gz") -> dict[str, str]:
"""تجزئة جميع الملفات المطابقة بشكل متوازٍ باستخدام الخيوط."""
files = list(Path(directory).glob(pattern))
results = {}
with ThreadPoolExecutor(max_workers=os.cpu_count()) as pool:
for path, digest in pool.map(hash_file, files):
results[path] = digest
return results
# تجزئة جميع ملفات الإصدار بشكل متوازٍ
checksums = hash_directory("/var/releases", "*.tar.gz")
for path, digest in checksums.items():
print(f"{digest} {path}")استخدام أجزاء 64 كيلوبايت بدلاً من 8 كيلوبايت يُقلل عدد الاستدعاءات من Python إلى C بمقدار 8 أضعاف. تعمل الخيوط جيداً هنا لأن GIL يُحرَّر خلال التجزئة على مستوى C — الاختناق هو في الإدخال/الإخراج للقرص وليس في المعالج.
مخرجات الطرفية مع تمييز بناء الجملة
مكتبة rich مفيدة حين تحتاج التحقق من دفعة ملفات وتريد جدولاً يُظهر حالة النجاح/الفشل لكل ملف بدلاً من تدفق المخرجات السداسية الخام.
pip install rich
import hashlib
from pathlib import Path
from rich.console import Console
from rich.table import Table
console = Console()
def hash_and_display(files: list[str], expected: dict[str, str]) -> None:
"""تجزئة الملفات وعرض النتائج مع رمز لوني للتحقق."""
table = Table(title="التحقق من SHA-256")
table.add_column("الملف", style="cyan")
table.add_column("SHA-256", style="dim", max_width=20)
table.add_column("الحالة")
for filepath in files:
h = hashlib.sha256()
with open(filepath, "rb") as f:
for chunk in iter(lambda: f.read(8192), b""):
h.update(chunk)
digest = h.hexdigest()
name = Path(filepath).name
status = "[green]✓ OK[/green]" if expected.get(name) == digest else "[red]✗ MISMATCH[/red]"
table.add_row(name, f"{digest[:16]}...", status)
console.print(table)
# الاستخدام
expected_checksums = {
"api-gateway-v3.1.tar.gz": "a8f5f167f44f4964...",
"worker-v3.1.tar.gz": "7d3f8c2a1b9e4f5d...",
}
hash_and_display(
["/var/releases/api-gateway-v3.1.tar.gz", "/var/releases/worker-v3.1.tar.gz"],
expected_checksums,
)console.print(data, highlight=False) أو وجّهها إلى ملف بـ Console(file=open(...)).العمل مع الملفات الكبيرة
نمط .update() المجزأ يتعامل مع ملفات بأي حجم باستخدام ذاكرة ثابتة. للملفات الكبيرة جداً (صور قرص بعدة جيجابايتات، نسخ احتياطية لقواعد البيانات)، ينتقل الاهتمام الرئيسي من الذاكرة إلى تغذية راجعة للمستخدم — تجزئة 10 جيجابايت بسرعة 500 ميجابايت/ثانية تستغرق 20 ثانية، والصمت خلال هذا الوقت يجعل المستخدم يظن أن البرنامج تعطّل.
import hashlib
import os
def sha256_with_progress(filepath: str) -> str:
"""تجزئة ملف كبير مع تقرير التقدم إلى stderr."""
file_size = os.path.getsize(filepath)
h = hashlib.sha256()
bytes_read = 0
with open(filepath, "rb") as f:
while chunk := f.read(1 << 20): # أجزاء 1 ميجابايت
h.update(chunk)
bytes_read += len(chunk)
pct = (bytes_read / file_size) * 100
print(f"\r جارٍ التجزئة: {pct:.1f}% ({bytes_read >> 20} ميجابايت / {file_size >> 20} ميجابايت)",
end="", flush=True)
print() # سطر جديد بعد شريط التقدم
return h.hexdigest()
digest = sha256_with_progress("/mnt/backups/db-snapshot-2026-03.sql.gz")
print(f"SHA-256: {digest}")NDJSON / JSON Lines — تجزئة كل سجل على حدة
import hashlib
import json
def hash_ndjson_records(filepath: str) -> dict[str, str]:
"""تجزئة كل سجل JSON في ملف NDJSON لإزالة التكرارات."""
seen = {}
with open(filepath, "r", encoding="utf-8") as f:
for line_num, line in enumerate(f, 1):
line = line.strip()
if not line:
continue
try:
record = json.loads(line)
# توحيد قبل التجزئة: ترتيب المفاتيح للمخرجات الحتمية
canonical = json.dumps(record, sort_keys=True, separators=(",", ":"))
digest = hashlib.sha256(canonical.encode("utf-8")).hexdigest()
if digest in seen:
print(f"السطر {line_num}: مكرر من السطر {seen[digest]}")
else:
seen[digest] = line_num
except json.JSONDecodeError:
print(f"السطر {line_num}: JSON غير صالح، تم التخطي")
print(f"تمت معالجة {line_num} سطراً، {len(seen)} سجلاً فريداً")
return seen
hash_ndjson_records("telemetry-events-2026-03.ndjson")hashlib.sha256(data) إلى حلقة .update() المجزأة عندما تتجاوز الملفات 50–100 ميجابايت. تحت هذا الحد، قراءة الملف بأكمله بـ f.read() مقبولة — سيكون استهلاك الذاكرة تقريباً مساوياً لحجم الملف.الأخطاء الشائعة
المشكلة: hashlib.sha256('text') يُثير TypeError: Unicode-objects must be encoded before hashing. الدالة تتطلب bytes وليس str.
الحل: شفّر النص أولاً: hashlib.sha256('text'.encode('utf-8')). أو استخدم b'' للقيم المكتوبة مباشرةً.
import hashlib
digest = hashlib.sha256("deployment-v4.2.1".encode("utf-8")).hexdigest()
# يعمل — يُعيد سلسلة سداسية من 64 حرفاًimport hashlib
digest = hashlib.sha256("deployment-v4.2.1").hexdigest()
# TypeError: Unicode-objects must be encoded before hashingالمشكلة: العامل == يتوقف عند أول بايت مختلف. يمكن للمهاجم قياس وقت الاستجابة لتخمين التوقيع الصحيح بايتاً بايتاً.
الحل: استخدم hmac.compare_digest() لجميع المقارنات الأمنية الحساسة — يعمل في وقت ثابت بغض النظر عن موضع الاختلاف.
received_sig = request.headers["X-Signature"]
expected_sig = hmac.new(key, body, hashlib.sha256).hexdigest()
if hmac.compare_digest(received_sig, expected_sig): # وقت ثابت
process_webhook(body)received_sig = request.headers["X-Signature"]
expected_sig = hmac.new(key, body, hashlib.sha256).hexdigest()
if received_sig == expected_sig: # عرضة لهجمات التوقيت
process_webhook(body)المشكلة: base64.b64encode(digest.hexdigest().encode()) ينتج سلسلة من 88 حرفاً — ضعف الـ 44 المتوقعة. ستُرفض من الـ APIs التي تتوقع SHA-256 مُشفَّراً بـ Base64.
الحل: استدعِ .digest() (بايتات خام) قبل ترميز Base64 وليس .hexdigest() (سلسلة سداسية).
import hashlib, base64 raw = hashlib.sha256(data).digest() b64 = base64.b64encode(raw) # 44 حرفاً — صحيح
import hashlib, base64 hex_str = hashlib.sha256(data).hexdigest() b64 = base64.b64encode(hex_str.encode()) # 88 حرفاً — خطأ!
المشكلة: hashlib.sha256(open('large.iso', 'rb').read()) يُحمّل الملف بأكمله في الذاكرة. ملف بحجم 4 جيجابايت يتطلب 4 جيجابايت من الذاكرة لمجرد حساب التجزئة.
الحل: اقرأ في أجزاء مع حلقة و.update(). استهلاك الذاكرة يظل ثابتاً بغض النظر عن حجم الملف.
import hashlib
h = hashlib.sha256()
with open("disk.iso", "rb") as f:
for chunk in iter(lambda: f.read(8192), b""):
h.update(chunk)
digest = h.hexdigest() # استهلاك ذاكرة ثابتimport hashlib
# يُحمّل ملف 4 جيجابايت بأكمله في الذاكرة
digest = hashlib.sha256(open("disk.iso", "rb").read()).hexdigest()hashlib مقابل hmac مقابل البدائل — مقارنة سريعة
للتجزئة المباشرة — المجاميع الاختبارية ومفاتيح التخزين المؤقت وبصمات المحتوى — التزم بـ hashlib.sha256(). انتقل إلى hmac.new() فور احتياجك مفتاحاً سرياً (webhook، توقيعات API، مصادقة الرموز). الجأ إلى مكتبة cryptography فقط إذا كان مشروعك يستخدمها أصلاً للتشفير أو TLS — إضافة اعتماد على امتداد C فقط من أجل التجزئة مبالغة حين يكون hashlib مدعوماً بالفعل بـ OpenSSL.
هل يمكن فك تشفير SHA-256؟ — الفرق بين التجزئة والتشفير
الإجابة المختصرة: لا. SHA-256 دالة أحادية الاتجاه. الخوارزمية مصممة لتكون غير قابلة للعكس — لا يمكنك إعادة بناء المدخل الأصلي من الملخص بحجم 256 بت. هذه ليست قيوداً في التنفيذ؛ إنها خاصية رياضية لدالة التجزئة. فضاء المخرجات البالغ 256 بت ضخم بصورة فلكية (2256 قيمة ممكنة)، والدالة تتخلى عن المعلومات خلال 64 جولة ضغط.
يمكن للمهاجمين محاولة هجمات القوة الغاشمة أو القاموس ضد المدخلات الضعيفة (كلمات المرور الشائعة والنصوص القصيرة)، لكن لأي مدخل بإنتروبيا معقولة — مفاتيح API، رموز عشوائية، محتوى ملفات — عكس SHA-256 غير ممكن حسابياً بالأجهزة الحالية. إذا احتجت إلى تحويل قابل للعكس، استخدم التشفير المتماثل:
# التجزئة — أحادية الاتجاه، لا يمكن استرداد الأصل import hashlib digest = hashlib.sha256(b"secret-config-value").hexdigest() # لا طريقة للحصول على "secret-config-value" من الملخص # التشفير — ثنائي الاتجاه، يمكن فك التشفير بالمفتاح from cryptography.fernet import Fernet key = Fernet.generate_key() cipher = Fernet(key) encrypted = cipher.encrypt(b"secret-config-value") decrypted = cipher.decrypt(encrypted) print(decrypted) # b"secret-config-value" — استُرد الأصل
لطريقة سريعة بدون تثبيت أي شيء لتوليد تجزئة SHA-256، الأداة الأونلاين تعمل كلياً في متصفحك.
كيف تتحقق مما إذا كانت سلسلة نصية تجزئة SHA-256 صالحة في Python
ملخص SHA-256 السداسي الصالح هو بالضبط 64 حرفاً سداسياً عشرياً (0-9، a-f، A-F). التحقق السريع قبل معالجة المدخلات غير الموثوقة يمنع الأخطاء المُربكة في المراحل اللاحقة.
import re
def is_sha256_hex(value: str) -> bool:
"""التحقق مما إذا كانت السلسلة تطابق صيغة ملخص SHA-256 السداسي."""
return bool(re.fullmatch(r"[a-fA-F0-9]{64}", value))
# حالات اختبار
print(is_sha256_hex("e3b0c44298fc1c149afbf4c8996fb924"
"27ae41e4649b934ca495991b7852b855")) # True — SHA-256 للسلسلة الفارغة
print(is_sha256_hex("e3b0c44298fc1c14")) # False — قصير جداً
print(is_sha256_hex("zzzz" * 16)) # False — أحرف سداسية غير صالحةالأسئلة الشائعة
كيف أجزّئ نصاً بـ SHA-256 في Python؟
استدعِ hashlib.sha256() مع تشفير النص إلى بايتات. النصوص في Python هي Unicode، وتعمل دوال التجزئة على بايتات خام، لذا يجب استدعاء .encode("utf-8") أولاً. تُعيد الدالة .hexdigest() السلسلة السداسية العشرية المعهودة من 64 حرفاً.
import hashlib
api_key = "sk_live_9f3a7b2e1d4c"
digest = hashlib.sha256(api_key.encode("utf-8")).hexdigest()
print(digest)
# e3b7c4a1f8d2...64 حرفاً سداسياًهل يمكن فك تشفير ملخص SHA-256 للحصول على النص الأصلي؟
لا. SHA-256 دالة أحادية الاتجاه — تحوّل مدخلات ذات طول اعتباطي إلى مخرجات ثابتة بحجم 256 بت وتفقد البنية الأصلية في العملية. لا يوجد معكوس رياضي. يمكن للمهاجمين محاولة هجمات القوة الغاشمة أو جداول قوس قزح ضد المدخلات الضعيفة (كلمات المرور القصيرة والكلمات الشائعة)، لكن لأي مدخل بإنتروبيا معقولة، عكس SHA-256 غير ممكن حسابياً. إذا احتجت إلى تحويل قابل للعكس، استخدم التشفير (AES-GCM أو Fernet) بدلاً من التجزئة.
ما الفرق بين .digest() و .hexdigest()؟
تُعيد .digest() البايتات الخام الـ 32 للملخص كـ bytes. تُعيد .hexdigest() البيانات ذاتها مشفّرة كسلسلة سداسية عشرية من 64 حرفاً بأحرف صغيرة. استخدم .digest() حين تحتاج مخرجات ثنائية — للتغذية في HMAC أو ترميز Base64 أو الكتابة في البروتوكولات الثنائية. استخدم .hexdigest() حين تحتاج سلسلة مقروءة للتسجيل أو التخزين في قاعدة البيانات أو مقارنة المجاميع الاختبارية.
import hashlib h = hashlib.sha256(b"deployment-v4.2.1") print(len(h.digest())) # 32 (bytes) print(len(h.hexdigest())) # 64 (hex characters)
كيف أحسب المجموع الاختباري SHA-256 لملف في Python؟
افتح الملف في وضع ثنائي وأدخله إلى أداة التجزئة في أجزاء عبر .update(). في Python 3.11+ استخدم hashlib.file_digest() للحصول على واجهة برمجية أبسط. لا تستدعِ f.read() على الملفات الكبيرة — فذلك يحمّل الملف بأكمله في الذاكرة.
import hashlib
def sha256_file(path: str) -> str:
h = hashlib.sha256()
with open(path, "rb") as f:
for chunk in iter(lambda: f.read(8192), b""):
h.update(chunk)
return h.hexdigest()
print(sha256_file("release-v4.2.1.tar.gz"))كيف أنشئ توقيع HMAC-SHA256 في Python؟
استخدم وحدة hmac مع hashlib.sha256 كـ digestmod. مرّر المفتاح السري والرسالة كـ bytes. الناتج هو ملخص مشفّر بمفتاح يُثبت كلاً من سلامة البيانات وأصالتها — يحتاج المستقبِل المفتاح ذاته للتحقق.
import hmac
import hashlib
secret = b"webhook_secret_9f3a"
payload = b'{"event":"payment.completed","amount":4999}'
signature = hmac.new(secret, payload, hashlib.sha256).hexdigest()
print(signature) # HMAC بـ 64 حرفاً سداسياًكيف أتحقق مما إذا كانت سلسلة نصية تمثّل ملخص SHA-256 صالحاً؟
ملخص SHA-256 السداسي العشري هو بالضبط 64 حرفاً سداسياً عشرياً. استخدم تعبيراً نمطياً أو فحص بسيط للطول والأحرف. أسلوب التعبير النمطي هو الأكثر وضوحاً.
import re
def is_sha256(s: str) -> bool:
return bool(re.fullmatch(r"[a-fA-F0-9]{64}", s))
print(is_sha256("e3b0c44298fc1c149afbf4c8996fb924"
"27ae41e4649b934ca495991b7852b855")) # True
print(is_sha256("not-a-hash")) # Falseأدوات ذات صلة
Dmitri is a DevOps engineer who relies on Python as his primary scripting and automation language. He builds internal tooling, CI/CD pipelines, and infrastructure automation scripts that run in production across distributed teams. He writes about the Python standard library, subprocess management, file processing, encoding utilities, and the practical shell-adjacent Python that DevOps engineers use every day.
Maria is a backend developer specialising in Python and API integration. She has broad experience with data pipelines, serialisation formats, and building reliable server-side services. She is an active member of the Python community and enjoys writing practical, example-driven guides that help developers solve real problems without unnecessary theory.