API کی توثیق اور اجازت: میکانزم، ٹریڈ آفس، اور ناکامی کے طریقوں میں انجینئرنگ کا گہرا غوطہ

ہر API کے پاس تصدیق کی کچھ شکل ہوتی ہے۔ لیکن سند حاصل کرنا اور اسے درست کرنا دو بالکل مختلف چیزیں ہیں۔

ہم نے ایک پروڈکشن سسٹم کا جائزہ لیا جہاں JWTs کی میعاد ختم نہیں ہوئی تھی۔ ایک ایسا نظام جہاں API کیز کو سورس کوڈ میں ہارڈ کوڈ کیا جاتا ہے اور عوامی ذخیرے کے لیے پابند کیا جاتا ہے۔ OAuth ری ڈائریکٹ URI ایک ایسا نظام ہے جو وائلڈ کارڈز استعمال کرتا ہے۔ یہ ایک ایسا نظام ہے جو مالیاتی APIs میں استعمال ہوتا ہے جہاں بنیادی تصدیق HTTPS ہونے کی توقع کی جاتی ہے، لیکن کسی نے اس کی تصدیق نہیں کی۔

ان میں سے ہر ایک ایک زندہ کمزوری تھی جو استحصال کے منتظر تھی۔

ان میں سے زیادہ تر مسائل لاپرواہ انجینئرز کی وجہ سے نہیں ہوتے۔ وہ انجینئرز سے آتے ہیں جو سمجھتے ہیں کہ میکانزم کو کیسے کام کرنا ہے، لیکن ناکامی کے طریقوں کو نہیں سمجھتے۔ انہیں کسی نے نہیں بتایا کہ جب یہ ٹوٹتا ہے تو کیا ہوتا ہے۔ کسی نے یہ نہیں بتایا کہ تنظیم کے معیارات کیا ہیں۔ انہوں نے جو کچھ وہ جانتے تھے لے لیا، کوڈ کا جائزہ لینے کے لیے اسے کافی حد تک نافذ کیا، اور آگے بڑھ گئے۔

یہ مضمون اس کو تبدیل کرنے کے بارے میں ہے۔ نہ صرف یہ جانیں کہ ہر میکانزم کیسے کام کرتا ہے، بلکہ یہ بھی جانیں کہ انہیں کب استعمال کرنا ہے، کب استعمال نہیں کرنا ہے، اور یہ کہ وہ پیداوار میں کیسے ناکام ہوتے ہیں۔

سب سے پہلے، آئیے اس الجھن کو دور کرتے ہیں جو حقیقی کمزوریوں کا سبب بنتا ہے۔ مصدقہ جواب: آپ کون ہیں؟ مصدقہ جواب: آپ کیا کر سکتے ہیں؟

ایک ایسا نظام جو مکمل طور پر تصدیق کرتا ہے لیکن مناسب اجازت کا فقدان ہے پھر بھی غیر مجاز ڈیٹا فراہم کرے گا۔ وہ سسٹم جو بالکل درست لیکن صرف کمزور طور پر توثیق کرتے ہیں انہیں آسانی سے نظرانداز کر دیا جاتا ہے۔ دونوں کو آزادانہ طور پر درست ہونا چاہیے۔

انڈیکس

شرائط

اس مضمون کو پڑھنے سے پہلے، آپ کو درج ذیل سے واقف ہونا چاہیے:

  • API کیا ہے اور HTTP درخواستیں اور جوابات کیسے کام کرتے ہیں؟

  • ٹوکن یا سیشن کیا ہے اس کی بنیادی سمجھ

  • عام سافٹ ویئر آرکیٹیکچر کے تصورات: گیٹ وے اور سروس لیئر

  • ڈارٹ یا C# نحو کا علم

سیکیورٹی کے پس منظر کی ضرورت نہیں ہے۔ یہاں تمام تصورات کی وضاحت انجینئرنگ کے نقطہ نظر سے کی گئی ہے۔

بنیادی باتیں: میکانزم کا انتخاب کرنے سے پہلے آپ کے پاس کیا ہونا چاہیے۔

اس سے پہلے کہ آپ یہ سوچیں کہ کون سا طریقہ کار استعمال کرنا ہے، آپ کے پاس تین چیزیں ہونی چاہئیں۔ ان طریقہ کار کے بغیر، کوئی طریقہ کار مدد نہیں کرے گا.

1. TLS اختیاری نہیں ہے۔

تمام APIs HTTPS پر بات چیت کرتے ہیں۔ تمام اختتامی نقطہ اور ماحول، نہ صرف پیداوار۔ یہ صرف اختتامی نقطہ نہیں ہے جو کارڈ نمبروں پر کارروائی کرتا ہے۔ ان سب کے

TLS کے بغیر، اس دستاویز میں کسی بھی طریقہ کار کو روکا جا سکتا ہے۔ بنیادی تصدیقی ٹوکن، API کیز، بیئرر ٹوکن، اور JWTs سبھی HTTP ہیڈر میں جاتے ہیں۔ HTTP ہیڈر TLS کے بغیر سادہ متن ہیں۔

آپ کے بنیادی ڈھانچے کو کم از کم TLS 1.2 نافذ کرنا چاہیے۔ TLS 1.0 اور 1.1 میں کمزوریاں معلوم ہیں۔ SSLv3 بری طرح ٹوٹ گیا ہے۔ اگر کوئی کلائنٹ پرانے پروٹوکول ورژن پر گفت و شنید کرنے کی کوشش کرتا ہے، تو انفراسٹرکچر پرت کو کنکشن کو مسترد کرنا چاہیے۔ یہ کنفیگریشن کا فیصلہ ہے نہ کہ کوئی ایسی چیز جسے آپ اپنے کوڈ میں سنبھالتے ہیں۔

2. عوامی ٹولز کو مناسب کنٹرول کے بغیر پروڈکشن APIs تک رسائی حاصل کرنے کے قابل نہیں ہونا چاہیے۔

مناسب رسائی کنٹرول کے بغیر پوسٹ مین یا سویگر کے ذریعے انٹرنیٹ پر قابل رسائی ایک پروڈکشن API ایک مسئلہ ہے جس کا انتظار کرنا ہے۔

ڈیولپمنٹ اور ٹیسٹنگ کو پروڈکشن ڈیٹا تک رسائی کے بغیر علیحدہ اسناد کے ساتھ سرشار ماحول کا استعمال کرنا چاہیے۔

3. پیداواری ڈیٹا کو ترقی یا جانچ کے ماحول میں کاپی نہیں کیا جانا چاہیے۔

یہ صرف اچھی مشق نہیں ہے۔ نائیجیریا کے NDPA 2023 کے تحت، ذاتی ڈیٹا پر صرف واضح، واضح اور قانونی مقاصد کے لیے کارروائی کی جانی چاہیے۔ پیداوار کے ذاتی ڈیٹا کو ترقیاتی ماحول میں کاپی کرنے سے براہ راست قانونی نمائش پیدا ہوتی ہے۔ PCI-DSS میں کسی بھی ایسے ماحول کی تعمیل شامل ہے جو کارڈ ہولڈر کے ڈیٹا کو اسٹور، پروسیس، یا منتقل کرتا ہے۔

انجینئرنگ کا جواب ہمیشہ مصنوعی ٹیسٹ ڈیٹا اور کسی بھی غیر پیداواری ماحول سے گمنام ڈیٹا سیٹ ہوتا ہے۔

اس کا اطلاق کرنے والے سات میکانزم درج ذیل ہیں۔

1. بنیادی تصدیق

یہ کیسے کام کرتا ہے۔

کلائنٹ ہر درخواست کے ساتھ صارف نام اور پاس ورڈ بھیجتا ہے۔ اسناد کو اس طرح ملایا گیا ہے: username:passwordیہ Base64 کو انکوڈ کیا گیا ہے اور اجازت کے ہیڈر میں رکھا گیا ہے۔

Authorization: Basic am9objpzZWNyZXQxMjM=

انکوڈ شدہ تار ہے۔ john:secret123 بیس 64 میں۔ Base64 خفیہ کاری نہیں ہے۔ انکوڈنگ۔ کوئی بھی جو ان ہیڈر کو پکڑتا ہے وہ آن لائن دستیاب Base64 ڈیکوڈر کا استعمال کرتے ہوئے انہیں سیکنڈوں میں ڈی کوڈ کر سکتا ہے۔

ڈارٹ:

// server-side basic auth validation
String? extractBasicAuthCredentials(Request request) {
  final authHeader = request.headers['authorization'];
  if (authHeader == null || !authHeader.startsWith('Basic ')) return null;

  final encoded = authHeader.substring(6);
  final decoded = utf8.decode(base64.decode(encoded));
  return decoded; 
}

Handler basicAuthMiddleware(Handler handler, UserService userService) {
  return (Request request) async {
    final credentials = extractBasicAuthCredentials(request);
    if (credentials == null) {
      return Response.unauthorized(
        'Missing credentials',
        headers: {'WWW-Authenticate': 'Basic realm="API"'},
      );
    }

    final parts = credentials.split(':');
    if (parts.length != 2) return Response.unauthorized('Invalid credentials');

    final isValid = await userService.validateCredentials(parts[0], parts[1]);
    if (!isValid) return Response.unauthorized('Invalid credentials');

    return handler(request);
  };
}

aspirate#:

public class BasicAuthHandler : AuthenticationHandler
{
    private readonly IUserService _userService;

    protected override async Task HandleAuthenticateAsync()
    {
        if (!Request.Headers.ContainsKey("Authorization"))
            return AuthenticateResult.Fail("Missing Authorization header");

        var authHeader = Request.Headers["Authorization"].ToString();
        if (!authHeader.StartsWith("Basic "))
            return AuthenticateResult.Fail("Invalid Authorization scheme");

        var encoded = authHeader.Substring(6);
        var decoded = Encoding.UTF8.GetString(Convert.FromBase64String(encoded));
        var parts = decoded.Split(':');

        if (parts.Length != 2)
            return AuthenticateResult.Fail("Invalid credentials format");

        var isValid = await _userService.ValidateCredentials(parts[0], parts[1]);
        if (!isValid)
            return AuthenticateResult.Fail("Invalid credentials");

        var claims = new[] { new Claim(ClaimTypes.Name, parts[0]) };
        var identity = new ClaimsIdentity(claims, Scheme.Name);
        var principal = new ClaimsPrincipal(identity);
        var ticket = new AuthenticationTicket(principal, Scheme.Name);

        return AuthenticateResult.Success(ticket);
    }
}

بنیادی توثیق کے ساتھ حقیقی مسائل

اسناد ہر درخواست کے ساتھ منتقل کی جاتی ہیں۔ درخواست کو مستقل طور پر روکنا حملہ آور کو آپ کا صارف نام اور پاس ورڈ فراہم کرتا ہے۔ کوئی میعاد ختم ہونے کی تاریخ نہیں ہے۔ اسے منسوخ نہیں کیا جا سکتا سوائے اپنا پاس ورڈ تبدیل کرنے کے۔ Base64 کسی بھی طرح کی سیکیورٹی فراہم نہیں کرتا ہے۔

بنیادی توثیق کے اختتامی نقطوں پر شرح محدود نہ ہونا وحشیانہ حملوں کی کھلی دعوت ہے۔ ایک حملہ آور جس کے پاس عام پاس ورڈز کی فہرست ہے ان سب کو منظم طریقے سے آزمائے گا۔ اگر انہیں کچھ نہیں روکتا ہے تو وہ بالآخر حملہ کر دیں گے۔

کب استعمال کریں۔

بنیادی تصدیق ایک مضبوطی سے کنٹرول شدہ ماحول میں اندرونی سرور سے سرور مواصلات کے لیے کام کرتی ہے جہاں کنکشن ہمیشہ خفیہ ہوتے ہیں اور API کی سطح انٹرنیٹ کے سامنے نہیں آتی ہے۔ کبھی بھی صارف کا سامنا کرنے والے APIs، کوئی بھی چیز جو حساس ڈیٹا کو ہینڈل کرتی ہے، یا TLS کے بغیر کوئی بھی چیز استعمال نہ کریں۔

2. API کلید

API کلید ایک منفرد، خفیہ تار ہے جسے سرور اس کی شناخت کے لیے کلائنٹ کو جاری کرتا ہے۔ ایک کلید اس وقت جاری کی جاتی ہے جب آپ فریق ثالث کی خدمت، جیسے کہ ادائیگی کا گیٹ وے یا SMS پلیٹ فارم استعمال کرنے کے لیے اندراج کرتے ہیں۔ آپ کی درخواست اس سروس سے جو بھی درخواست کرتی ہے اس میں وہ کلید شامل ہوتی ہے، تاکہ سروس جان سکے کہ کون کال کر رہا ہے، استعمال کو ٹریک کر سکتا ہے، اور درخواست پر درست اجازتوں اور شرح کی حدوں کا اطلاق کر سکتا ہے۔

صارف سے کوئی تعلق نہیں ہے۔ یہ آپ کی درخواست سے منسلک ہے۔ یہ API کیز اور صارف کی تصدیق کے ٹوکن کے درمیان بنیادی فرق ہے۔

یہ کیسے کام کرتا ہے۔

ایک جامد خفیہ تار کلائنٹ کو جاری کیا جاتا ہے اور ہر درخواست کے ہیڈر میں بھیجا جاتا ہے۔

X-API-Key: sk_live_abc123xyz

ڈارٹ:

class ApiKeyService {
  final ApiKeyRepository _repository;

  ApiKeyService(this._repository);

  Future> validateApiKey(
    String apiKey,
    String callerDomain,
  ) async {
    final keyRecord = await _repository.findByKey(apiKey);

    if (keyRecord == null) {
      return Result.failure(AppException.unauthorized('Invalid API key'));
    }

    if (keyRecord.isExpired) {
      return Result.failure(AppException.unauthorized('API key has expired'));
    }

    if (keyRecord.isRevoked) {
      return Result.failure(AppException.unauthorized('API key has been revoked'));
    }

    // validate that the calling domain is allowed for this key
    if (!keyRecord.allowedDomains.contains(callerDomain)) {
      return Result.failure(
        AppException.forbidden('Calling domain not authorized for this API key'),
      );
    }

    return Result.success(ApiKeyContext(
      clientId: keyRecord.clientId,
      environment: keyRecord.environment,
      allowedScopes: keyRecord.allowedScopes,
    ));
  }
}

Handler apiKeyMiddleware(Handler handler, ApiKeyService apiKeyService) {
  return (Request request) async {
    final apiKey = request.headers['x-api-key'];
    if (apiKey == null || apiKey.isEmpty) {
      return Response(401, body: jsonEncode({'error': 'API key required'}));
    }

    final origin = request.headers['origin'] ?? request.headers['host'] ?? '';
    final result = await apiKeyService.validateApiKey(apiKey, origin);

    if (result.isFailure) {
      return Response(403, body: jsonEncode({'error': result.error?.message}));
    }

    return handler(request);
  };
}

aspirate#:

public class ApiKeyMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IApiKeyService _apiKeyService;

    public async Task InvokeAsync(HttpContext context)
    {
        if (!context.Request.Headers.TryGetValue("X-API-Key", out var apiKey))
        {
            context.Response.StatusCode = 401;
            await context.Response.WriteAsync("API key required");
            return;
        }

        var callerDomain = context.Request.Headers["Origin"].ToString()
            ?? context.Request.Host.Value;

        var result = await _apiKeyService.ValidateApiKey(apiKey, callerDomain);

        if (!result.IsSuccess)
        {
            context.Response.StatusCode = 403;
            await context.Response.WriteAsync(result.Error);
            return;
        }

        context.Items["ApiKeyContext"] = result.Value;
        await _next(context);
    }
}

API کیز کے ساتھ اصل مسئلہ

API کیز جامد ہیں۔ یہ خود بخود ختم نہیں ہوتا ہے۔ عوامی GitHub ذخیروں، Slack پیغامات، یا لاگ فائلوں میں پائی جانے والی کلیدیں اس وقت تک لائیو اسناد ہوتی ہیں جب تک کہ کوئی انہیں نوٹس نہ لے اور ان کی جگہ لے لے۔

ایک سب سے عام فرق جو میں بڑی تنظیموں میں دیکھ رہا ہوں وہ یہ ہے کہ ایک سے زیادہ کلائنٹس کے ذریعہ بلائے گئے APIs میں ڈومین وائٹ لسٹ نہیں ہوتی ہے۔ ایک ہی کلید تمام ڈومینز میں کام کرتی ہے۔ یہ آپ کو کلائنٹس اور ماحول میں چابیاں بانٹنے کی اجازت دیتا ہے۔ اس کا مطلب ہے کہ سٹیجنگ کیز کو پروڈکشن میں بلایا جا سکتا ہے، موبائل کیز ویب کلائنٹس کے ذریعے استعمال کی جا سکتی ہیں، اور دونوں کے درمیان کوئی حقیقی حد نہیں ہے۔

API کیز کو متعدد کلائنٹس یا متعدد ماحول میں کام نہیں کرنا چاہیے۔ چابیاں مخصوص وائٹ لسٹ شدہ ڈومینز اور مخصوص ماحول سے منسلک ہونی چاہئیں۔ یہ اختیاری نہیں ہے۔

اپنے سورس کوڈ میں API کیز کو ہارڈ کوڈ نہ کریں۔ کبھی بھی گٹ کا عہد نہ کریں۔ .gitignore یہ کافی نہیں ہے۔ رن ٹائم پر چابیاں ایک قابل اعتماد خفیہ مینیجر (والٹس، Azure ایپ کنفیگریشن، AWS سیکرٹس مینیجر) سے حاصل کی جانی چاہئیں۔ API کیز کو گھومنا ایک منصوبہ بند تنظیمی عمل ہونا چاہیے، نہ کہ مشتبہ خلاف ورزی کا جواب۔

کب استعمال کریں۔

سرور سے سرور مواصلات، عوامی APIs جہاں کال کرنے والوں کی شناخت اور شرح محدود کرنے کی ضرورت ہے، اور ڈویلپر ٹولز اور انضمام کے لیے API کیز استعمال کریں۔ کوئی بھی منظر جہاں انسانی صارف براہ راست کال کرنے والا نہیں ہے۔

3. بیئرر ٹوکن کی تصدیق

یہ کیسے کام کرتا ہے۔

کلائنٹ لاگ ان فلو کے ذریعے ایک بار تصدیق کرتا ہے اور اسے ایک ٹوکن ملتا ہے۔ یہ ٹوکن بعد کی تمام درخواستوں کے اجازت نامے کے ہیڈر میں جاتا ہے۔

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

آپ کے پہلے لاگ ان کے بعد، آپ کے پاس کوئی اسناد نہیں ہوں گی۔ ٹوکن منتقل کرنے کے لیے ہیں۔ سرور ہر درخواست کے لیے ٹوکن کی توثیق کرتا ہے۔

ڈارٹ:

class BearerTokenMiddleware {
  final TokenValidator _validator;

  BearerTokenMiddleware(this._validator);

  Handler call(Handler handler) {
    return (Request request) async {
      final authHeader = request.headers['authorization'];

      if (authHeader == null || !authHeader.startsWith('Bearer ')) {
        return Response(401, body: jsonEncode({'error': 'Bearer token required'}));
      }

      final token = authHeader.substring(7);
      final validationResult = await _validator.validate(token);

      if (validationResult.isFailure) {
        return Response(401, body: jsonEncode({'error': validationResult.error?.message}));
      }

      final updatedRequest = request.change(
        context: {'auth_claims': validationResult.value},
      );

      return handler(updatedRequest);
    };
  }
}

aspirate#:

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = builder.Configuration["Jwt:Issuer"],
            ValidAudience = builder.Configuration["Jwt:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Secret"]!)
            ),
            ClockSkew = TimeSpan.Zero
        };
    });

بیئرر ٹوکن کے ساتھ اصل مسئلہ

ٹوکن چوری سب سے بڑا مسئلہ ہے۔ ایک بار جب حملہ آور ایک درست بیئرر ٹوکن حاصل کر لیتا ہے، تو وہ اسے اس وقت تک استعمال کر سکتے ہیں جب تک کہ ٹوکن کی میعاد ختم نہ ہو جائے یا اسے دستی طور پر منسوخ نہ کر دیا جائے۔ یہی وجہ ہے کہ ٹوکن کی میعاد ختم کرنا ضروری نہیں ہے۔ یہ نقصان کو محدود کرنے کے لیے ہے جب ٹوکنز کو نقصان پہنچے۔ ریفریش ٹوکن روٹیشن کے ساتھ ایک قلیل المدت رسائی ٹوکن درست نمونہ ہے۔

کب استعمال کریں۔

یہ سب سے زیادہ جدید ویب اور موبائل APIs، صارف کی توثیق کے بہاؤ، اور کسی بھی API کے ساتھ اچھی طرح سے کام کرتا ہے جس کے لیے اسٹیٹ لیس اور توسیع پذیر تصدیق کی ضرورت ہوتی ہے۔

4. JWT – JSON ویب ٹوکن

یہ کیسے کام کرتا ہے۔

JWT بیئرر ٹوکن کا ایک مخصوص فارمیٹ ہے نہ کہ ایک علیحدہ تصدیقی طریقہ کار کے۔ یہ ایک اسٹینڈ ٹوکن ہے جو ٹوکن کے اندر ہی صارف کے بارے میں دعوے کرتا ہے۔

JWT کے تین حصے نقطوں سے الگ ہوتے ہیں۔

Header.Payload.Signature
eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiIxMjMiLCJyb2xlIjoiYWRtaW4ifQ.SIGNATURE

ہیڈر دستخطی الگورتھم کی وضاحت کرتا ہے۔ پے لوڈ میں صارف کی شناخت، کردار، میعاد ختم ہونے کا وقت، اور جاری کرنے کا وقت جیسے دعوے شامل ہیں۔ دستخط ایک کرپٹوگرافک ہیش ہے جو ثابت کرتا ہے کہ ٹوکن سرور سے آیا ہے اور اس کے ساتھ چھیڑ چھاڑ نہیں کی گئی ہے۔

سرور خفیہ طور پر دستخط کی توثیق کرتا ہے اور اندر کے دعووں پر بھروسہ کرتا ہے۔ ڈیٹا بیس تلاش کرنے کی ضرورت نہیں ہے۔ یہی وہ چیز ہے جو JWT کو بے وطن اور قابل توسیع بناتی ہے۔

ڈارٹ:

class JwtService {
  final String _secret;
  final String _issuer;
  final Duration _accessTokenExpiry;

  JwtService({
    required String secret,
    required String issuer,
    Duration accessTokenExpiry = const Duration(minutes: 15),
  })  : _secret = secret,
        _issuer = issuer,
        _accessTokenExpiry = accessTokenExpiry;

  String generateAccessToken(User user) {
    final now = DateTime.now();
    final payload = {
      'sub': user.id,
      'role': user.role.name,
      'iat': now.millisecondsSinceEpoch ~/ 1000,
      'exp': now.add(_accessTokenExpiry).millisecondsSinceEpoch ~/ 1000,
      'iss': _issuer,
      
    };

    return _sign(payload);
  }

  Result validateToken(String token) {
    try {
      final claims = _verifyAndDecode(token);

      final exp = claims['exp'] as int;
      if (DateTime.fromMillisecondsSinceEpoch(exp * 1000).isBefore(DateTime.now())) {
        return Result.failure(AppException.unauthorized('Token has expired'));
      }

      if (claims['iss'] != _issuer) {
        return Result.failure(AppException.unauthorized('Invalid token issuer'));
      }

      return Result.success(JwtClaims.fromMap(claims));
    } on SignatureVerificationException {
      return Result.failure(AppException.unauthorized('Invalid token signature'));
    } catch (e) {
      return Result.failure(AppException.unauthorized('Token validation failed'));
    }
  }
}

aspirate#:

public class JwtService
{
    private readonly JwtSettings _settings;

    public string GenerateAccessToken(User user)
    {
        var securityKey = new SymmetricSecurityKey(
            Encoding.UTF8.GetBytes(_settings.Secret)
        );

       
        var credentials = new SigningCredentials(
            securityKey,
            SecurityAlgorithms.HmacSha256
        );

        var claims = new[]
        {
            new Claim(JwtRegisteredClaimNames.Sub, user.Id),
            new Claim(ClaimTypes.Role, user.Role.ToString()),
            new Claim(JwtRegisteredClaimNames.Iat,
                DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString()),
           
        };

        var token = new JwtSecurityToken(
            issuer: _settings.Issuer,
            audience: _settings.Audience,
            claims: claims,
            expires: DateTime.UtcNow.AddMinutes(15),
            signingCredentials: credentials
        );

        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}

JWT ناکامی موڈ

جب صحیح طریقے سے لاگو کیا جائے تو JWT بہترین ہے۔ غلط طریقے سے نافذ کیا گیا، یہ تباہ کن ہو سکتا ہے۔ تمام ناکامیاں نفاذ کی ناکامیاں ہیں، معیاری ناکامیاں نہیں۔ یہ کچھ ہے جو میں نے دیکھا ہے کہ حقیقی مسائل پیدا ہوتے ہیں:

1. الگورتھم کنفیوژن حملہ

JWT ہیڈر دستخط کرنے کے لیے استعمال ہونے والے الگورتھم کی وضاحت کرتا ہے۔ اگر سرور ٹوکن کے لیے مطلوبہ الگورتھم کو قبول کرتا ہے، تو حملہ آور الگورتھم کو اس پر سیٹ کرتا ہے: none دستخط کو مکمل طور پر ہٹا دیتا ہے۔ سرور تمام ٹوکنز کو درست تسلیم کرتا ہے۔

2. کمزور دستخطی راز

کمزور JWT رازوں کو زبردستی آف لائن کیا جا سکتا ہے۔ حملہ آور کو سرور تک رسائی کی ضرورت نہیں ہے۔ وہ ٹوکن لیتے ہیں، اسے کریکر کے ذریعے چلاتے ہیں، راز دریافت کرتے ہیں، اور اب مطلوبہ صارف کے طور پر جو بھی ٹوکن چاہتے ہیں اس پر دستخط کر سکتے ہیں۔

کم از کم 256 بٹس کا مضبوط انکرپشن سیکرٹ استعمال کریں۔ انتہائی محفوظ سیاق و سباق کے لیے، غیر متناسب کلیدوں کے ساتھ RS256 یا ES256 استعمال کریں۔

3. کوئی میعاد ختم نہیں ہوئی۔

جے ڈبلیو ٹی کے بغیر exp دعویٰ کبھی باطل نہیں ہوگا۔ ہمیشہ ایک میعاد ختم ہونے کی تاریخ مقرر کریں۔ قلیل المدت رسائی کے ٹوکنز کے لیے، 15 منٹ سے 1 گھنٹہ کا انتخاب کریں۔ ریفریش ٹوکن سیشن کے تسلسل کو سنبھالتے ہیں۔

4. پے لوڈ میں حساس ڈیٹا

پے لوڈ غیر انکرپٹڈ اور بیس 64 انکوڈ شدہ ہے۔ جو بھی ٹوکن حاصل کرتا ہے وہ اندر کی ہر چیز کو ڈکرپٹ اور پڑھ سکتا ہے۔ JWT پے لوڈ میں پاس ورڈ، مکمل اکاؤنٹ نمبر، BVN، یا حساس PII درج نہ کریں۔ اس کے بجائے، ایک شناخت کنندہ ڈالیں۔ اپنے سرورز کو حساس ڈیٹا حاصل کرنے دیں۔

5. واپسی کی کوئی حکمت عملی نہیں۔

JWTs بے وطن ہیں، اس لیے سرور جاری کردہ ٹوکن کو ٹریک نہیں کرتا ہے۔ چوری شدہ ٹوکن میعاد ختم ہونے تک درست ہیں۔

حل: واضح طور پر منسوخ شدہ ٹوکنز کے لیے ٹوکن بلیک لسٹ کو برقرار رکھ کر یا ریفریش ٹوکن روٹیشن کے ساتھ مختصر میعاد ختم کرنے کے ذریعے نقصان کی کھڑکی کو کم کریں۔

JWT کب استعمال کریں۔

بڑے پیمانے پر اسٹیٹ لیس APIs، مائیکرو سروسز کے لیے استعمال کریں جہاں سروس کو مرکزی تصدیقی سرور، اور موبائل ایپلیکیشنز کو کال کیے بغیر ہر درخواست کے لیے اپنی شناخت کی تصدیق کرنی ہوگی۔ یہ کسی بھی سسٹم کے لیے موزوں ہے جہاں اسٹیٹ لیس توثیق کی پیمائش ٹوکن منسوخی کے انتظام کی پیچیدگی سے زیادہ اہم ہے۔

5. OAuth 2.0

یہ کیسے کام کرتا ہے۔

OAuth 2.0 ایک تصدیقی فریم ورک ہے، تصدیقی پروٹوکول نہیں۔ یہ صارفین کو تیسرے فریق کے ساتھ اپنے پاس ورڈ شیئر کیے بغیر فریق ثالث ایپلی کیشنز کو اپنے وسائل تک رسائی دینے کی اجازت دیتا ہے۔

آپ نے اس خصوصیت کو ہر بار استعمال کیا ہے جب آپ Google کا استعمال کرتے ہوئے کسی ایپ میں سائن ان کرتے ہیں، یا جب بھی آپ کو "اس ایپ کو اپنے اکاؤنٹ تک رسائی کی اجازت دیں” نظر آتا ہے۔

اس میں چار فریق شامل ہیں: اجازت دینے والا سرور جو ٹوکن جاری کرتا ہے، ریسورس سرور جو محفوظ API کی میزبانی کرتا ہے، کلائنٹ، جو رسائی کی درخواست کرنے والی ایپلیکیشن ہے، اور وسائل کا مالک، جو صارف ہے۔

تصدیقی کوڈ کا بہاؤ اس طرح کام کرتا ہے:

  1. کلائنٹ صارف کو ایک مخصوص دائرہ کار کی درخواست کے ساتھ اجازت دینے والے سرور پر بھیجتا ہے۔

  2. صارف درخواست کردہ دائرہ کار کی تصدیق اور منظوری دیتا ہے۔

  3. اجازت دینے والا سرور اجازت کے کوڈ کے ساتھ کلائنٹ کو واپس بھیجتا ہے۔

  4. کلائنٹ سرور سائیڈ پر رسائی ٹوکن کے لیے ایک کوڈ کا تبادلہ کرتا ہے۔

  5. کلائنٹ ریسورس سرور کو کال کرنے کے لیے رسائی ٹوکن کا استعمال کرتا ہے۔

ڈارٹ:

class OAuthClient {
  final String _clientId;
  final String _clientSecret;
  final String _redirectUri;
  final String _authorizationEndpoint;
  final String _tokenEndpoint;

  OAuthClient({
    required String clientId,
    required String clientSecret,
    required String redirectUri,
    required String authorizationEndpoint,
    required String tokenEndpoint,
  })  : _clientId = clientId,
        _clientSecret = clientSecret,
        _redirectUri = redirectUri,
        _authorizationEndpoint = authorizationEndpoint,
        _tokenEndpoint = tokenEndpoint;

  String buildAuthorizationUrl(List scopes) {
   
    final state = _generateSecureState();

    final params = {
      'response_type': 'code',
      'client_id': _clientId,
      'redirect_uri': _redirectUri,
      'scope': scopes.join(' '),
      'state': state,
    };

    final uri = Uri.parse(_authorizationEndpoint)
        .replace(queryParameters: params);

    return uri.toString();
  }

  Future> exchangeCodeForTokens(
    String code,
    String state,
    String expectedState,
  ) async {
   
    if (state != expectedState) {
      return Result.failure(
        AppException.unauthorized('Invalid state parameter'),
      );
    }

    final response = await http.post(
      Uri.parse(_tokenEndpoint),
      headers: {'Content-Type': 'application/x-www-form-urlencoded'},
      body: {
        'grant_type': 'authorization_code',
        'code': code,
        'redirect_uri': _redirectUri,
        'client_id': _clientId,
        'client_secret': _clientSecret,
      },
    );

    if (response.statusCode != 200) {
      return Result.failure(AppException.unauthorized('Token exchange failed'));
    }

    final tokens = OAuthTokens.fromJson(jsonDecode(response.body));
    return Result.success(tokens);
  }

  String _generateSecureState() {
    final bytes = List.generate(32, (_) => Random.secure().nextInt(256));
    return base64Url.encode(bytes);
  }
}

aspirate#:

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = "OAuth2";
})
.AddCookie()
.AddOAuth("OAuth2", options =>
{
    options.ClientId = builder.Configuration["OAuth:ClientId"]!;
    options.ClientSecret = builder.Configuration["OAuth:ClientSecret"]!;
    options.CallbackPath = "/auth/callback";
    options.AuthorizationEndpoint = "https://auth.provider.com/authorize";
    options.TokenEndpoint = "https://auth.provider.com/token";
    options.SaveTokens = true;
    options.Scope.Add("openid");
    options.Scope.Add("profile");

    options.Events = new OAuthEvents
    {
        OnCreatingTicket = async context =>
        {
            var userInfoRequest = new HttpRequestMessage(
                HttpMethod.Get,
                "https://auth.provider.com/userinfo"
            );
            userInfoRequest.Headers.Authorization =
                new AuthenticationHeaderValue("Bearer", context.AccessToken);

            var response = await context.Backchannel.SendAsync(userInfoRequest);
            var userInfo = await response.Content.ReadFromJsonAsync();

            context.Identity!.AddClaim(new Claim(
                ClaimTypes.NameIdentifier,
                userInfo!.RootElement.GetString("sub")!
            ));
        }
    };
});

OAuth 2.0 ناکامی کے موڈز

1. غلط ترتیب شدہ ری ڈائریکٹ URI

اگر توثیقی سرور ری ڈائریکٹ URIs کی سختی سے توثیق نہیں کرتا ہے، حملہ آور اپنے URIs کو تبدیل کر سکتے ہیں اور تصدیقی کوڈ کو روک سکتے ہیں۔ اس سے بچنے کے لیے، عین مطابق میچ چیکنگ کا استعمال کریں۔

2. URL میں ٹوکن

رسائی ٹوکنز سرور لاگ، براؤزر کی تاریخ، یا حوالہ دینے والے ہیڈر میں ظاہر ہو سکتے ہیں کیونکہ کوئی انہیں تصدیقی ہیڈر کے بجائے استفسار کے پیرامیٹرز میں رکھتا ہے۔ ٹوکن کا تعلق اجازت کے ہیڈر سے ہے۔ URL لاگ میں ظاہر ہوتا ہے، لیکن توثیق کا ہیڈر نہیں دکھاتا ہے۔

OAuth 2.0 کب استعمال کریں۔

یہ کسی بھی منظر نامے میں اچھی طرح سے کام کرتا ہے جہاں آپ کو صارف کے وسائل تک رسائی تیسرے فریق کو سونپنے کی ضرورت ہوتی ہے، بشمول سماجی لاگ ان، کراس آرگنائزیشن API انضمام، اور پارٹنر سسٹم انٹیگریشن۔

6. اوپن آئی ڈی کنیکٹ (OIDC)

یہ کیسے کام کرتا ہے۔

OAuth 2.0 تصدیق کو ہینڈل کرتا ہے۔ OpenID Connect OAuth 2.0 کے اوپر تصدیق کا اضافہ کرتا ہے۔ ہم آپ کو صرف یہ نہیں بتاتے کہ آپ کیا منظور کرتے ہیں۔ یہ دراصل آپ کو بتاتا ہے کہ صارف کون ہے۔

OIDC رسائی ٹوکن کے ساتھ ایک ID ٹوکن جاری کرتا ہے۔ ایک ID ٹوکن ایک JWT ہے جس میں تصدیق شدہ شناختی دعوے شامل ہیں، بشمول موضوع کا شناخت کنندہ، ای میل، نام، پروفائل تصویر، اور تصدیق کب ہوئی ہے۔

ڈارٹ:

class OidcService {
  final String _issuer;
  final String _clientId;
  final JwtValidator _jwtValidator;

  OidcService({
    required String issuer,
    required String clientId,
    required JwtValidator jwtValidator,
  })  : _issuer = issuer,
        _clientId = clientId,
        _jwtValidator = jwtValidator;

  Future> validateIdToken(
    String idToken,
  ) async {
    final claimsResult = await _jwtValidator.validate(idToken);
    if (claimsResult.isFailure) {
      return Result.failure(claimsResult.error!);
    }

    final claims = claimsResult.value!;

    if (claims['iss'] != _issuer) {
      return Result.failure(AppException.unauthorized('Invalid token issuer'));
    }


    final aud = claims['aud'];
    final audiences = aud is List ? aud : [aud];
    if (!audiences.contains(_clientId)) {
      return Result.failure(
        AppException.unauthorized('Token not intended for this client'),
      );
    }

    return Result.success(UserIdentity(
      subject: claims['sub'] as String,
      email: claims['email'] as String?,
      name: claims['name'] as String?,
      emailVerified: claims['email_verified'] as bool? ?? false,
    ));
  }
}

aspirate#:

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
    options.Authority = "https://accounts.google.com";
    options.ClientId = builder.Configuration["OIDC:ClientId"]!;
    options.ClientSecret = builder.Configuration["OIDC:ClientSecret"]!;
    options.ResponseType = "code";
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Scope.Add("email");
    options.SaveTokens = true;
    options.GetClaimsFromUserInfoEndpoint = true;

    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        NameClaimType = "name",
        RoleClaimType = "role"
    };
});

OIDC کب استعمال کریں۔

کسی بھی ایپلیکیشن کے لیے مثالی ہے جس کے لیے ایک قابل اعتماد شناخت فراہم کنندہ، جیسے کہ انٹرپرائز SSO یا سوشل لاگ ان کے ذریعے صارف کی شناخت کی تصدیق کی ضرورت ہے۔ یہ کسی بھی ایسے نظام کے لیے موزوں ہے جو صارف کی اسناد کو براہ راست منظم کرنے کے بجائے کسی قابل اعتماد تیسرے فریق کو شناخت کی تصدیق سونپنا چاہتا ہے۔

Google سائن ان، Microsoft Azure AD، Okta، اور Auth0 سبھی OIDC کو نافذ کرتے ہیں۔ اگر آپ کا سوال صرف "کیا یہ درخواست منظور ہے” نہیں ہے بلکہ "یہ شخص کون ہے؟” پھر OIDC صحیح فریم ورک ہے۔

7. باہمی TLS (mTLS)

یہ کیسے کام کرتا ہے۔

سادہ TLS میں، کلائنٹ سرور کے سرٹیفکیٹ کی تصدیق کرتا ہے۔ سرور کسی بھی کلائنٹ پر بھروسہ کرتا ہے جس کے ساتھ وہ کنکشن قائم کر سکتا ہے۔

باہمی TLS میں، دونوں فریق ایک دوسرے کے سرٹیفکیٹس کی تصدیق کرتے ہیں۔ سرور صرف ان کلائنٹس سے کنکشن قبول کرتا ہے جو قابل اعتماد سرٹیفکیٹ اتھارٹی کی طرف سے جاری کردہ سرٹیفکیٹ استعمال کرتے ہیں۔ کلائنٹ اپنی شناخت نہیں بنا سکتے کیونکہ انہیں حقیقی سرٹیفکیٹ کی ضرورت ہوتی ہے۔

کوئی بیئرر ٹوکن یا API کلید نہیں ہے۔ ایک سرٹیفکیٹ ایک تصدیق ہے۔

ڈارٹ (کلائنٹ سائڈ mTLS):

class MtlsHttpClient {
  final http.Client _client;

  MtlsHttpClient._internal(this._client);

  static Future create({
    required String certificatePath,
    required String privateKeyPath,
    required String trustedCaPath,
  }) async {
    final context = SecurityContext(withTrustedRoots: false);

    // load the client certificate
    context.useCertificateChainBytes(
      await File(certificatePath).readAsBytes(),
    );

    // load the client private key
    context.usePrivateKeyBytes(
      await File(privateKeyPath).readAsBytes(),
    );

    // only trust this specific CA
    context.setTrustedCertificatesBytes(
      await File(trustedCaPath).readAsBytes(),
    );

    final httpClient = HttpClient(context: context);
    final client = IOClient(httpClient);

    return MtlsHttpClient._internal(client);
  }

  Future get(String url, {Map? headers}) {
    return _client.get(Uri.parse(url), headers: headers);
  }

  Future post(
    String url, {
    Map? headers,
    Object? body,
  }) {
    return _client.post(Uri.parse(url), headers: headers, body: body);
  }
}

aspirate#:

builder.WebHost.ConfigureKestrel(options =>
{
    options.ConfigureHttpsDefaults(httpsOptions =>
    {
        httpsOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
        httpsOptions.ClientCertificateValidation = (certificate, chain, errors) =>
        {
            if (errors != SslPolicyErrors.None)
                return false;

            var expectedThumbprint = "your-trusted-cert-thumbprint";
            return certificate.Thumbprint == expectedThumbprint;
        };
    });
});

public class MtlsMiddleware
{
    private readonly RequestDelegate _next;

    public async Task InvokeAsync(HttpContext context)
    {
        var clientCert = context.Connection.ClientCertificate;

        if (clientCert == null)
        {
            context.Response.StatusCode = 401;
            await context.Response.WriteAsync("Client certificate required");
            return;
        }

        if (!IsValidClientCertificate(clientCert))
        {
            context.Response.StatusCode = 403;
            await context.Response.WriteAsync("Invalid client certificate");
            return;
        }

        await _next(context);
    }

    private bool IsValidClientCertificate(X509Certificate2 cert)
    {
        if (cert.NotAfter < DateTime.UtcNow) return false;

        var trustedThumbprints = new HashSet
        {
            "THUMBPRINT_SERVICE_A",
            "THUMBPRINT_SERVICE_B",
        };

        return trustedThumbprints.Contains(cert.Thumbprint);
    }
}

mTLS کے ساتھ اصل مسئلہ

یہاں مسئلہ سرٹیفکیٹ کے انتظام کا ہے۔ آپ کے سرٹیفکیٹ کی میعاد ختم ہو رہی ہے۔ اگر گردش خودکار نہیں ہے تو، میعاد ختم ہونے والے سرٹیفکیٹس بدترین ممکنہ لمحے میں خدمات کے درمیان رابطے کو توڑ دیں گے۔ CA کا بنیادی ڈھانچہ خود محفوظ ہونا چاہیے۔ سمجھوتہ شدہ CA کا مطلب ہے کہ تمام جاری کردہ سرٹیفکیٹس سے سمجھوتہ کیا گیا ہے۔

مکمل PKI کو منظم کرنے کے لیے آپریشنل صلاحیتوں کے بغیر ٹیموں کے لیے، سخت ڈومین وائٹ لسٹ اور گردشی شیڈول کے ساتھ API کیز زیادہ عملی جواب ہو سکتی ہیں۔ mTLS ایک صحیح فن تعمیر ہے، لیکن صحیح حاصل کرنا سب سے مشکل فن تعمیر بھی ہے۔

ایم ٹی ایل ایس کب استعمال کریں۔

انتہائی محفوظ خدمات، جیسے کہ ادائیگی کے گیٹ ویز یا بینکنگ APIs کے درمیان مواصلت کے لیے mTLS استعمال کریں۔ یہ ریگولیٹڈ ماحول میں مائیکرو سروسز کے لیے بھی مثالی ہے جن کی تعمیل کے لیے ٹرانسپورٹ کی پرت پر خفیہ شناختی ثبوت کی ضرورت ہوتی ہے۔ ایک انتہائی محفوظ نظام میں، اندرونی خدمات کے درمیان تمام مواصلات کو حساس سمجھا جانا چاہیے۔ mTLS وہ بنیاد فراہم کرتا ہے۔

صحیح طریقہ کار کا انتخاب

تصدیق کے طریقہ کار کا انتخاب ایک تعمیراتی فیصلہ ہے۔ فریم ورک مندرجہ ذیل ہے:

صارف کا سامنا کرنے والی ویب اور موبائل ایپلیکیشنز کے لیے: JWT کے بطور بیئرر ٹوکن منتخب کریں۔ یہ گھومنے والے ریفریش ٹوکن کے ساتھ ایک مختصر مدت تک رسائی کا ٹوکن ہے۔ تمام تصدیقی اختتامی پوائنٹس کے لیے شرح کو محدود کرنا۔

تیسرے فریق کی تفویض کردہ رسائی کے لیے: OAuth 2.0 استعمال کریں۔ اگر آپ کو بھی صارف کی شناخت کی توثیق کرنے کی ضرورت ہے تو سب سے اوپر OIDC شامل کریں۔

انٹرپرائز SSO کے لیے: اپنے انٹرپرائز شناخت فراہم کنندہ کے ساتھ OpenID Connect کا انتخاب کریں۔

کم سرور سے سرور سیکیورٹی کی ضروریات۔ ڈومین وائٹ لسٹ، ماحول کے لیے مخصوص کیز، اور طے شدہ گردش کے ساتھ API کیز استعمال کریں۔

ایک ریگولیٹڈ، ہائی سیکورٹی ماحول میں خدمات کے درمیان: mTLS استعمال کریں۔

مضبوطی سے کنٹرول شدہ ماحول میں اندرونی ٹولز کے لیے: بنیادی تصدیق صرف اس صورت میں ممکن ہے جب TLS کی ضمانت ہو۔ باقی سب کے لیے، مضبوط استعمال کریں۔

آپ کو کال کرنے والا کون ہے، ڈیٹا کی حساسیت کیا ہے، اور آپ کی تعمیل کے تقاضے کیا ہیں اس کی بنیاد پر آپ کو ایک تصدیقی طریقہ کار کا انتخاب کرنا چاہیے۔ یہ کوئی کنونشن یا کوئی چیز نہیں ہے جسے میں نے اپنے آخری پروجیکٹ میں استعمال کیا۔ لاگو کرنے کا سب سے آسان طریقہ نہیں ہے.

تنظیمی نظم و ضبط جو ہر چیز کو آپس میں جوڑتا ہے۔

ٹکنالوجی کے نفاذ کو درست کرنا آدھا کام ہے۔ باقی نصف تنظیمی ہے۔

API کلیدی گردشوں کو شیڈول اور فعال ہونا چاہئے، نہ کہ مشتبہ خلاف ورزی کا ردعمل۔ ہر کلید کا ایک متعین زیادہ سے زیادہ لائف ٹائم اور انجینئرنگ کی ملکیت میں گردش کا شیڈول ہوتا ہے۔

API کیز متعدد کلائنٹس یا متعدد ماحول کے ساتھ کام نہیں کرتی ہیں۔ ایک اسٹیجنگ کلید ایک اسٹیجنگ کلید ہے۔ موبائل کلائنٹ کی کلید موبائل کلائنٹ کی ہے۔ پورے ماحول میں کلیدی دوبارہ استعمال سیکیورٹی کی حدود کو توڑتا ہے۔

راز ماخذ کوڈ، ایپلیکیشن کوڈ، یا ریپوزٹری سے وابستہ کنفیگریشن فائلوں میں موجود نہیں ہیں۔ رن ٹائم کے وقت ایک قابل اعتماد خفیہ مینیجر سے راز حاصل کیے جاتے ہیں۔ یہ انجینئرنگ کا معیار ہے، ترجیح نہیں۔

انکرپشن الگورتھم آپ کی تنظیم کے لیے ایک معیاری ہونا چاہیے، نہ کہ ایسی چیز جس کا فیصلہ ڈویلپرز پروجیکٹ بہ پروجیکٹ کی بنیاد پر کریں۔ اسٹاف انجینئر یا آرکیٹیکٹ کی سطح پر کوئی فرد تنظیم کے ذریعہ استعمال کردہ الگورتھم، طریقوں اور کلیدی لمبائی کی وضاحت کرتا ہے۔ تمام پروجیکٹ معیارات کا استعمال کرتے ہیں اور ڈویلپرز ایک پراجیکٹ بہ پروجیکٹ کی بنیاد پر شروع سے خفیہ کاری کو لاگو نہیں کرتے ہیں۔

اداروں کو کرپٹوگرافک آپریشنز کے لیے اندرونی طور پر مشترکہ پیکجز بنانا اور برقرار رکھنا چاہیے۔ ڈویلپر پیکج درآمد کرتا ہے۔ وہ خود خفیہ کاری نہیں لکھتے ہیں۔ یہ ایڈہاک انتخاب کی وجہ سے خفیہ کاری کے نفاذ کی ناکامیوں کے پورے زمرے کو ختم کرتا ہے۔

فیلڈ لیول ماسکنگ کے ساتھ سٹرکچرڈ لاگنگ کو فریم ورک کی سطح پر لاگو کیا جانا چاہیے۔ توثیق کے ہیڈر، ٹوکن، پاس ورڈ، اکاؤنٹ نمبر، اور حساس فیلڈز کبھی بھی کسی بھی ماحول (پروڈکشن، سٹیجنگ، یا ڈیولپمنٹ) کے لاگ میں ظاہر نہیں ہونے چاہئیں۔ ماسکنگ لاگنگ فریم ورک کی سطح پر لاگو کی جاتی ہے، لہذا انفرادی ڈویلپرز غلطی سے حساس ڈیٹا کو لاگ ان نہیں کر سکتے چاہے وہ کوشش کریں۔

نتیجہ

اس دستاویز میں موجود تمام میکانزم کام کریں گے اگر درست طریقے سے لاگو کیا جائے۔ ایک ہی وقت میں، اگر غلط طریقے سے لاگو کیا جاتا ہے تو تمام میکانزم پیش گوئی اور دستاویزی طریقوں میں ناکام ہوجاتے ہیں۔

ایک JWT الگورتھم کنفیوژن اٹیک کے نتیجے میں اصل توثیق بائی پاس ہوئی۔ غلط کنفیگر شدہ OAuth ری ڈائریکٹ URI کی وجہ سے حقیقی دنیا کا اکاؤنٹ ٹیک اوور ہوا۔ لاپتہ اسٹیٹ پیرامیٹر نے ایک حقیقی CSRF حملے کو فعال کیا۔ دستخط کی کمزوری کی وجہ سے بڑے پیمانے پر حقیقی دنیا کی نقالی ہوئی ہے۔ ریپوزٹری میں ہارڈ کوڈ شدہ API کیز نے پروڈکشن سسٹم کو غیر مجاز رسائی کے لیے بے نقاب کیا۔

یہ نظریاتی ناکامی کا موڈ نہیں ہے۔ یہ تمام سائز کی تنظیموں میں پیداواری نظام میں موجود ہے۔ وہ انجینئر جنہوں نے یہ نظام بنایا وہ نااہل نہیں تھے۔ انہوں نے ناکامی کے طریقوں کے بارے میں نہیں سنا ہے۔ کوئی بھی تنظیمی معیارات کی وضاحت یا پائپ لائن میں ان کو نافذ نہیں کر رہا تھا۔

انجینئرنگ ڈسپلن یہ ہے کہ آپ کوڈ کی پہلی لائن لکھنے سے پہلے یہ جاننا کہ ہر طریقہ کار کس طرح کام کرتا ہے، اور ان ناکامی طریقوں کو شروع سے روکنے کے لیے اپنے نفاذ کو تیار کرنا ہے۔ یہ توثیق کے درمیان فرق ہے جو کام کرتا ہے اور توثیق جو مخالف حالات میں زندہ رہتا ہے۔

مبارک کوڈنگ!

اوپر تک سکرول کریں۔