-
Notifications
You must be signed in to change notification settings - Fork 9
Security Best Practices
Hassaan Ali edited this page Dec 7, 2025
·
1 revision
Security guidelines for using the JazzCash package safely and securely.
Bad:
// Don't hardcode credentials
$merchantId = '12345';
$password = 'secret_password';
$hashKey = 'secret_key';Good:
// Use environment variables
$merchantId = config('jazzcash.merchant_id');
$password = config('jazzcash.password');
$hashKey = config('jazzcash.hash_key');-
Never commit
.envto version control -
Use
.env.examplefor documentation -
Restrict file permissions:
chmod 600 .env - Use different credentials for sandbox and production
- Rotate credentials regularly
Always use HTTPS for:
- API calls to JazzCash
- Payment callbacks
- Return URLs
- All payment-related URLs
// Ensure HTTPS in production
if (app()->environment('production')) {
URL::forceScheme('https');
}Always validate user input:
$request->validate([
'amount' => 'required|numeric|min:0.01',
'billref' => 'required|string|max:255|regex:/^[A-Za-z0-9\-_]+$/',
'productDescription' => 'required|string|max:500',
]);Sanitize data before using:
$billRef = htmlspecialchars($request->billref, ENT_QUOTES, 'UTF-8');
$description = filter_var($request->description, FILTER_SANITIZE_STRING);Bad:
// Don't trust callback without verification
if ($request->input('pp_ResponseCode') === '000') {
// Process payment
}Good:
// Always verify hash first
if ($this->verifyHash($request->all())) {
if ($request->input('pp_ResponseCode') === '000') {
// Process payment
}
} else {
// Reject callback
Log::warning('Invalid hash in callback', ['ip' => $request->ip()]);
return response()->json(['error' => 'Invalid request'], 403);
}private function verifyHash(array $data): bool
{
// Rebuild hash array in same order as sent
$hashArray = [
$data['pp_Amount'] ?? '',
$data['pp_BankID'] ?? '',
$data['pp_BillReference'] ?? '',
// ... all fields in order
];
$sortedArray = config('jazzcash.hash_key');
foreach ($hashArray as $value) {
if ($value !== 'undefined' && $value !== null && $value !== '') {
$sortedArray .= '&' . $value;
}
}
$expectedHash = hash_hmac('sha256', $sortedArray, config('jazzcash.hash_key'));
return hash_equals($expectedHash, $data['pp_SecureHash'] ?? '');
}Consider implementing IP whitelisting:
public function handleCallback(Request $request)
{
$allowedIPs = [
'203.0.113.0', // JazzCash IP 1
'203.0.113.1', // JazzCash IP 2
// Get actual IPs from JazzCash support
];
if (!in_array($request->ip(), $allowedIPs)) {
Log::warning('Callback from unauthorized IP', ['ip' => $request->ip()]);
return response()->json(['error' => 'Unauthorized'], 403);
}
// Process callback
}Add callback route to CSRF exceptions:
// app/Http/Middleware/VerifyCsrfToken.php
protected $except = [
'payment/callback',
'api/payment/callback',
];Bad:
Log::info('Payment data', [
'password' => $password,
'hash_key' => $hashKey,
]);Good:
Log::info('Payment initiated', [
'amount' => $amount,
'bill_reference' => $billRef,
// Don't log sensitive data
]);If storing payment data, encrypt it:
use Illuminate\Support\Facades\Crypt;
// Encrypt
$encrypted = Crypt::encryptString($sensitiveData);
// Decrypt
$decrypted = Crypt::decryptString($encrypted);Bad:
catch (\Exception $e) {
return response()->json([
'error' => $e->getMessage(), // May contain sensitive info
'trace' => $e->getTraceAsString(), // Security risk
]);
}Good:
catch (\Exception $e) {
Log::error('Payment error', [
'message' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
return response()->json([
'error' => 'Payment processing failed. Please try again.',
], 500);
}Log security-related events:
Log::warning('Suspicious payment activity', [
'ip' => $request->ip(),
'user_agent' => $request->userAgent(),
'bill_reference' => $billRef,
]);The package automatically escapes HTML in form generation. However, if you're generating custom HTML:
// Always escape output
echo htmlspecialchars($userInput, ENT_QUOTES, 'UTF-8');The package includes HTML escaping in renderPage() method. This prevents XSS attacks if user input is used in payment data.
- Never commit credentials - Use environment variables
- Use HTTPS - Always encrypt data in transit
- Validate inputs - Never trust user input
- Verify hash - Always verify callback hash
- Log securely - Don't log sensitive data
- Handle errors securely - Don't expose sensitive info
- Use IP whitelisting - For callbacks (optional)
- Rotate credentials - Update keys periodically
- Monitor logs - Check for suspicious activity
- Keep updated - Apply security patches
If processing cards directly (not applicable to hosted checkout):
- Use secure networks - Firewalls, encryption
- Protect card data - Encryption, tokenization
- Vulnerability management - Regular scans, patches
- Access control - Restrict access to payment data
- Monitor and test - Regular security testing
- Encrypt personal data - At rest and in transit
- Implement access controls - Limit who can access data
- Log access - Track who accesses what data
- Data breach notification - Have a plan
- Troubleshooting - Common issues
- Configuration Guide - Secure configuration
- Payment Flow - Secure payment flow