# Security ## Secure Storage ### Installation ```bash yarn add react-native-keychain ``` ### Secure Storage Implementation ```typescript // src/utils/secureStorage.ts import * as Keychain from 'react-native-keychain'; export class SecureStorage { static async setItem(key: string, value: string): Promise { try { await Keychain.setInternetCredentials(key, key, value); } catch (error) { console.error('Error storing secure item:', error); throw error; } } static async getItem(key: string): Promise { try { const credentials = await Keychain.getInternetCredentials(key); return credentials ? credentials.password : null; } catch (error) { console.error('Error retrieving secure item:', error); return null; } } static async removeItem(key: string): Promise { try { await Keychain.resetInternetCredentials(key); } catch (error) { console.error('Error removing secure item:', error); throw error; } } static async clear(): Promise { try { await Keychain.resetGenericPassword(); } catch (error) { console.error('Error clearing secure storage:', error); throw error; } } // Biometric authentication static async setItemWithBiometrics(key: string, value: string): Promise { try { await Keychain.setInternetCredentials(key, key, value, { accessControl: Keychain.ACCESS_CONTROL.BIOMETRY_CURRENT_SET, authenticationType: Keychain.AUTHENTICATION_TYPE.DEVICE_PASSCODE_OR_BIOMETRICS, }); } catch (error) { console.error('Error storing item with biometrics:', error); throw error; } } static async getItemWithBiometrics(key: string): Promise { try { const credentials = await Keychain.getInternetCredentials(key, { authenticationType: Keychain.AUTHENTICATION_TYPE.DEVICE_PASSCODE_OR_BIOMETRICS, showModal: true, kLocalizedFallbackTitle: 'Please use your passcode', }); return credentials ? credentials.password : null; } catch (error) { console.error('Error retrieving item with biometrics:', error); return null; } } } ``` ## Data Encryption ### Encryption Utilities ```typescript // src/utils/encryption.ts import CryptoJS from 'crypto-js'; export class EncryptionService { private static readonly SECRET_KEY = 'your-secret-key-here'; // Should be from secure config static encrypt(text: string): string { try { return CryptoJS.AES.encrypt(text, this.SECRET_KEY).toString(); } catch (error) { console.error('Encryption error:', error); throw new Error('Failed to encrypt data'); } } static decrypt(encryptedText: string): string { try { const bytes = CryptoJS.AES.decrypt(encryptedText, this.SECRET_KEY); return bytes.toString(CryptoJS.enc.Utf8); } catch (error) { console.error('Decryption error:', error); throw new Error('Failed to decrypt data'); } } static hash(text: string): string { return CryptoJS.SHA256(text).toString(); } static generateSalt(): string { return CryptoJS.lib.WordArray.random(128/8).toString(); } static hashWithSalt(text: string, salt: string): string { return CryptoJS.SHA256(text + salt).toString(); } } ``` ## API Security ### Request Interceptors ```typescript // src/services/secureAPI.ts import axios, {AxiosRequestConfig, AxiosResponse} from 'axios'; import {SecureStorage} from '@utils/secureStorage'; import {EncryptionService} from '@utils/encryption'; const secureAPI = axios.create({ baseURL: 'https://api.saayam.com', timeout: 10000, }); // Request interceptor for authentication secureAPI.interceptors.request.use( async (config: AxiosRequestConfig) => { // Add authentication token const token = await SecureStorage.getItem('auth_token'); if (token) { config.headers = { ...config.headers, Authorization: `Bearer ${token}`, }; } // Add request signature const timestamp = Date.now().toString(); const signature = EncryptionService.hash( `${config.method}${config.url}${timestamp}` ); config.headers = { ...config.headers, 'X-Timestamp': timestamp, 'X-Signature': signature, }; // Encrypt sensitive data if (config.data && config.method === 'post') { config.data = { ...config.data, encrypted: true, payload: EncryptionService.encrypt(JSON.stringify(config.data)), }; } return config; }, (error) => { return Promise.reject(error); } ); // Response interceptor for decryption secureAPI.interceptors.response.use( (response: AxiosResponse) => { // Decrypt response if needed if (response.data?.encrypted) { try { response.data = JSON.parse( EncryptionService.decrypt(response.data.payload) ); } catch (error) { console.error('Failed to decrypt response:', error); } } return response; }, async (error) => { // Handle token refresh if (error.response?.status === 401) { try { const refreshToken = await SecureStorage.getItem('refresh_token'); if (refreshToken) { const response = await axios.post('/auth/refresh', { refreshToken, }); const newToken = response.data.token; await SecureStorage.setItem('auth_token', newToken); // Retry original request error.config.headers.Authorization = `Bearer ${newToken}`; return secureAPI.request(error.config); } } catch (refreshError) { // Redirect to login await SecureStorage.clear(); // Navigate to login screen } } return Promise.reject(error); } ); export default secureAPI; ``` ## Input Validation ### Validation Schemas ```typescript // src/utils/validation.ts import * as yup from 'yup'; export const validationSchemas = { email: yup .string() .email('Invalid email format') .required('Email is required') .matches( /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/, 'Invalid email format' ), password: yup .string() .required('Password is required') .min(8, 'Password must be at least 8 characters') .matches( /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/, 'Password must contain uppercase, lowercase, number and special character' ), phone: yup .string() .required('Phone number is required') .matches( /^\+?[1-9]\d{1,14}$/, 'Invalid phone number format' ), amount: yup .number() .required('Amount is required') .positive('Amount must be positive') .max(1000000, 'Amount cannot exceed 1,000,000'), }; export const sanitizeInput = (input: string): string => { return input .replace(/)<[^<]*)*<\/script>/gi, '') .replace(/[<>]/g, '') .trim(); }; export const validateAndSanitize = ( value: string, schema: yup.StringSchema ): {isValid: boolean; sanitized: string; error?: string} => { const sanitized = sanitizeInput(value); try { schema.validateSync(sanitized); return {isValid: true, sanitized}; } catch (error) { return { isValid: false, sanitized, error: error instanceof Error ? error.message : 'Validation failed', }; } }; ``` ## Biometric Authentication ### Biometric Setup ```typescript // src/utils/biometricAuth.ts import TouchID from 'react-native-touch-id'; import {Alert, Platform} from 'react-native'; export class BiometricAuth { static async isSupported(): Promise { try { const biometryType = await TouchID.isSupported(); return !!biometryType; } catch (error) { return false; } } static async getSupportedType(): Promise { try { const biometryType = await TouchID.isSupported(); return biometryType; } catch (error) { return null; } } static async authenticate(reason: string = 'Authenticate to continue'): Promise { try { const optionalConfigObject = { title: 'Authentication Required', subtitle: reason, description: 'This app uses biometric authentication to protect your data', fallbackLabel: 'Use Passcode', cancelLabel: 'Cancel', disableDeviceFallback: false, showModal: true, kLocalizedFallbackTitle: 'Use Passcode', }; await TouchID.authenticate(reason, optionalConfigObject); return true; } catch (error: any) { console.error('Biometric authentication failed:', error); if (error.name === 'LAErrorUserFallback') { // User chose to use passcode return this.authenticateWithPasscode(); } return false; } } private static async authenticateWithPasscode(): Promise { return new Promise((resolve) => { Alert.prompt( 'Enter Passcode', 'Please enter your device passcode', [ {text: 'Cancel', onPress: () => resolve(false)}, { text: 'OK', onPress: (passcode) => { // In a real app, you would validate the passcode resolve(!!passcode); }, }, ], 'secure-text' ); }); } } ``` ## Certificate Pinning ### SSL Pinning Implementation ```typescript // src/utils/certificatePinning.ts import {NetworkingModule} from 'react-native'; export class CertificatePinning { private static readonly PINNED_CERTIFICATES = [ 'sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=', // Your server's certificate hash ]; static setupPinning() { if (Platform.OS === 'ios') { // iOS certificate pinning setup NetworkingModule.addRequestInterceptor((request: any) => { request.trusty = { hosts: [ { host: 'api.saayam.com', certificates: this.PINNED_CERTIFICATES, }, ], }; return request; }); } } static validateCertificate(hostname: string, certificate: string): boolean { return this.PINNED_CERTIFICATES.includes(certificate); } } ``` ## Security Headers ### Request Security Headers ```typescript // src/utils/securityHeaders.ts export const getSecurityHeaders = () => ({ 'X-Content-Type-Options': 'nosniff', 'X-Frame-Options': 'DENY', 'X-XSS-Protection': '1; mode=block', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains', 'Content-Security-Policy': "default-src 'self'", 'Referrer-Policy': 'strict-origin-when-cross-origin', }); ``` ## Security Best Practices ### Security Checklist ```typescript // src/utils/securityAudit.ts export class SecurityAudit { static performSecurityCheck(): {passed: boolean; issues: string[]} { const issues: string[] = []; // Check for debug mode in production if (__DEV__ && process.env.NODE_ENV === 'production') { issues.push('Debug mode is enabled in production'); } // Check for console logs in production if (process.env.NODE_ENV === 'production' && console.log.toString().includes('native code')) { issues.push('Console logs are not disabled in production'); } // Check for secure storage usage if (!this.isUsingSecureStorage()) { issues.push('Sensitive data is not stored securely'); } // Check for HTTPS usage if (!this.isUsingHTTPS()) { issues.push('API calls are not using HTTPS'); } return { passed: issues.length === 0, issues, }; } private static isUsingSecureStorage(): boolean { // Check if secure storage is properly implemented return true; // Implement actual check } private static isUsingHTTPS(): boolean { // Check if all API endpoints use HTTPS return true; // Implement actual check } } ```