Pinning Exceptions
Handling Pinning Exceptions¶
Certificate pinning is a critical security measure, but it introduces risks when exceptions occur—such as certificate mismatches, expired certificates, or revoked trust chains. Properly handling these scenarios ensures user trust, prevents crashes, and maintains security.
Detecting Pinning Exceptions¶
Pinning exceptions are typically triggered during TLS handshakes. In Flutter, frameworks like http or dio provide mechanisms to intercept and handle these errors.
Example: Interceptor for SSL Errors¶
import 'package:dio/dio.dart';
import 'package:dio_interceptors/dio_interceptors.dart';
class SSLExceptionInterceptor extends Interceptor {
@override
void onError(DioException error, ErrorInterceptorHandler handler) {
if (error.type == DioExceptionType.receiveTimeout ||
error.type == DioExceptionType.sendTimeout) {
// Handle network timeouts
} else if (error.type == DioExceptionType.response) {
// Handle HTTP errors
} else if (error.type == DioExceptionType.other) {
// Check for certificate mismatch or expiration
final sslError = error.error as SSLException;
if (sslError != null && sslError.cert != null) {
final certificate = sslError.cert;
final now = DateTime.now();
if (certificate.notBefore.isAfter(now) || certificate.notAfter.isBefore(now)) {
// Certificate is expired or not yet valid
await showNotification('Certificate Expired: ${certificate.subject}');
print('Certificate expired: ${certificate.subject}');
} else {
// Check SAN for mismatch
if (!certificate.subjectAltNames.contains('expected.san.example.com')) {
await showNotification('Certificate Mismatch: ${certificate.subject}');
print('Certificate mismatch: ${certificate.subject}');
}
}
}
} else if (error.type == DioExceptionType.cancel) {
// Handle request cancellation
} else {
// Fallback for unknown errors
print('Unknown error: ${error.message}');
}
handler.next(error);
}
}
Diagram: SSL Exception Detection Flow¶
[Request Sent]
|
v
[SSL Handshake]
|
v
[Exception Detected]
|
v
[Intercept and Handle Error]
|
v
[User Notified or Fallback Triggered]
Handling Expired Certificates¶
Expired certificates indicate a potential security risk. Apps should:
1. Validate certificate validity using the NotBefore and NotAfter fields.
2. Log the event for monitoring.
3. Notify users to check their connection or update the app.
Example: Checking Certificate Expiry¶
import 'dart:security';
Future<void> checkCertificateValidity(X509Certificate certificate) async {
final now = DateTime.now();
if (certificate.notBefore.isAfter(now) || certificate.notAfter.isBefore(now)) {
// Certificate is expired or not yet valid
await showNotification('Certificate Expired: $certificate.subject');
// Log the event for monitoring
print('Certificate expired: ${certificate.subject}');
}
}
User Notification and Fallback Mechanisms¶
When pinning fails, apps should:
- Avoid automatic retries to prevent infinite loops.
- Notify users via in-app dialogs or logs.
- Provide fallback options (e.g., redirecting to a trusted endpoint).
Example: User Notification Dialog¶
import 'package:flutter/material.dart';
void showNotification(String message) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('SSL Error'),
content: Text(message),
actions: [
TextButton(
onPressed: Navigator.of(context).pop,
child: Text('OK'),
),
],
),
);
}
Graceful Degradation Strategies¶
In rare cases, apps may need to:
- Retry with a different certificate (e.g., a fallback CA bundle).
- Redirect to a secure endpoint with a known valid certificate.
- Disable pinning temporarily for debugging (but only in development).
Note: These strategies should be used sparingly and with strict validation to avoid compromising security.
Security Considerations¶
- Avoid automatic overrides for pinning exceptions; this can expose the app to man-in-the-middle attacks.
- Implement HSTS headers to enforce HTTPS and prevent downgrade attacks.
- Monitor certificate validity regularly and update pinned certificates as needed.
Key takeaways¶
- Detect SSL errors using interceptors to handle pinning exceptions gracefully.
- Validate certificate expiry and notify users to maintain trust.
- Avoid automatic retries and prioritize user notification over fallbacks.
- Balance security and usability by avoiding temporary overrides in production.
- Monitor and update pinned certificates to ensure long-term security.
Note: The examples above are specific to Flutter/Dio. For cross-platform implementations, consider using standard Dart libraries like dart:io or other HTTP clients that provide similar SSL error handling capabilities.