Implementing Security Best Practices
1. Sanitizing User Input
| Input Type | Description | Sanitization Method | Notes |
|---|---|---|---|
| HTML Content | Untrusted HTML content from users | DOMPurify |
Prevents XSS attacks by stripping dangerous tags |
| User Text | Plain text input (e.g., comments, names) | escape-html |
Escapes HTML characters to prevent injection |
| URLs | User-provided URLs in links or redirects | validator.js |
Validates and sanitizes URLs to ensure they are safe |
Example: Using DOMPurify to Sanitize HTML
import DOMPurify from 'dompurify';
const dirty = '<script>alert("XSS")</script><p>Hello <b>World</b></p>';
const clean = DOMPurify.sanitize(dirty);
console.log(clean); // <p>Hello <b>World</b></p>
Example: Escaping User Text
import escapeHtml from 'escape-html';
const userInput = '<script>alert("Hello")</script>';
const escaped = escapeHtml(userInput);
console.log(escaped); // <script>alert("Hello")</script>
Note: Always sanitize user input before rendering it in the DOM or storing it in a database.
Warning: Never rely solely on client-side sanitization. Always validate and sanitize on the server as well.
2. Implementing Authentication
| Feature | Description | Implementation |
|---|---|---|
| Authentication Flow | OAuth 2.0 or OpenID Connect for secure login | import { AuthModule } from '@ionic/auth'; |
| Token Management | JWT-based tokens with refresh logic | const token = await auth.getToken(); |
| Session Handling | Automatic session timeout and re-authentication | auth.onSessionExpired(() => { ... }); |
Example: Setting up Auth in Ionic
import { Auth } from '@ionic/auth';
const auth = new Auth({
auth0Domain: 'your-domain.auth0.com',
clientId: 'your-client-id'
});
auth.login().then(() => {
console.log('User logged in');
});
Note: Ensure all authentication flows are handled securely and tokens are stored in secure storage like
SecureStorage.
Warning: Never expose client secrets or sensitive tokens in frontend code.
3. Using HTTPS Connections
| Property | Description | Default | Notes |
|---|---|---|---|
| ssl.enabled | Enables or disables SSL/TLS encryption for network requests | false |
Must be enabled in production environments |
| ssl.certificate | Path to the SSL certificate file (PEM format) | null |
Required if ssl.enabled is true |
| ssl.key | Path to the private key file (PEM format) | null |
Required if ssl.enabled is true |
| ssl.trustStore | Path to the trust store containing CA certificates | null |
Used for validating server certificates |
Example: Enabling HTTPS in Ionic App
import { HttpClientModule } from '@angular/common/http';
import { HttpsInterceptor } from './https.interceptor';
@NgModule({
imports: [
HttpClientModule
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: HttpsInterceptor,
multi: true
}
]
})
export class AppModule { }
Note: Ensure all API endpoints are accessed over HTTPS to prevent man-in-the-middle attacks.
Warning: Never hardcode SSL certificates or keys in your source code. Use environment variables or secure configuration files.
4. Storing Sensitive Data
| Storage Method | Description | Security Level | Notes |
|---|---|---|---|
| localStorage | localStorage.setItem('key', 'value') |
Limited | Not secure for sensitive data; accessible via JavaScript |
| sessionStorage | sessionStorage.setItem('key', 'value') |
Limited | Same risks as localStorage; cleared on session end |
| Encrypted Database (SQLite) | const db = new SQLite('encrypted.db'); |
Good | Secure if properly encrypted and key managed |
| Secure HTTP Headers | Content-Security-Policy: default-src 'self' |
Good | Prevents XSS and data leakage |
| Environment Variables | process.env.API_KEY |
Good | Not accessible in client-side code; must be injected at build time |
Example: Securely Storing API Keys
import { Capacitor } from '@capacitor/core';
import { SecureStoragePlugin } from '@ionic-native/secure-storage';
if (Capacitor.isNativePlatform()) {
const secureStorage = new SecureStoragePlugin();
secureStorage.set({ key: 'api_key', value: process.env.API_KEY });
}
Note: Never store sensitive data in plain text or client-side storage. Use platform-specific secure storage when available.
5. Implementing OAuth Flow
| Step | Description | Implementation |
|---|---|---|
| 1. Setup | Configure OAuth provider (e.g., Auth0, Firebase) | |
| 2. Redirect URL | Define redirect URI in OAuth provider settings | https://yourdomain.com/oauth/callback |
| 3. Initiate Auth | Redirect user to OAuth provider login page | |
| 4. Handle Callback | Receive and process OAuth response | |
Example: Ionic + Firebase Auth Setup
import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
const firebaseConfig = {
apiKey: "your-api-key",
authDomain: "your-app.firebaseapp.com",
};
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
// Sign in with Google
const provider = new GoogleAuthProvider();
signInWithPopup(auth, provider)
.then(result => {
const user = result.user;
console.log("Signed in as:", user.email);
})
.catch(error => {
console.error("Login error:", error);
});
Note: Ensure redirect URIs are whitelisted in your OAuth provider dashboard.
Warning: Never store sensitive credentials in client-side code.
6. Using Content Security Policy
| Directive | Description | Default Value | Example |
|---|---|---|---|
| default-src | Defines the default source for various resources | 'self' |
default-src 'self'; |
| script-src | Controls sources for JavaScript execution | 'self' |
script-src 'self' 'unsafe-inline'; |
| style-src | Controls sources for CSS stylesheets | 'self' |
style-src 'self' 'unsafe-inline'; |
| img-src | Controls sources for images | 'self' |
img-src 'self' data:; |
| connect-src | Controls sources for network requests | 'self' |
connect-src 'self' https://api.example.com; |
| font-src | Controls sources for font files | 'self' |
font-src 'self' https://fonts.googleapis.com; |
| object-src | Controls sources for embedded objects | 'none' |
object-src 'none'; |
| media-src | Controls sources for media elements | 'self' |
media-src 'self' blob:; |
| frame-src | Controls sources for embedded frames | 'self' |
frame-src 'self'; |
| base-uri | Controls the base URL for relative URLs | 'self' |
base-uri 'self'; |
Example: Setting up CSP in Ionic App
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https://api.example.com; font-src 'self' https://fonts.googleapis.com; object-src 'none'; media-src 'self' blob:; frame-src 'self'; base-uri 'self';">
Note: The Content Security Policy (CSP) is a security feature that helps prevent cross-site scripting (XSS) and other code injection attacks. It is recommended to set a strict CSP for Ionic apps to enhance security.
Warning: Be cautious when using
'unsafe-inline' in script-src or style-src. It can make your app vulnerable to XSS attacks. Prefer using hash or nonce values for inline scripts and styles.
7. Preventing XSS Attacks
| Technique | Description | Implementation |
|---|---|---|
| DOMPurify | Sanitizes HTML to prevent XSS | import DOMPurify from 'dompurify';\nconst clean = DOMPurify.sanitize(dirtyHtml); |
| Angular Sanitization | Built-in HTML sanitization in Angular | import { DomSanitizer } from '@angular/platform-browser';\nconst safeHtml = sanitizer.bypassSecurityTrustHtml(htmlString); |
| Ionic Content Security Policy (CSP) | Restricts content sources to prevent XSS | <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline';"> |
Example: Using DOMPurify in Ionic
import DOMPurify from 'dompurify';
const dirtyHtml = '<script>alert("XSS")</script><p>Safe content</p>';
const cleanHtml = DOMPurify.sanitize(dirtyHtml);
console.log(cleanHtml); // <p>Safe content</p>
Note: Always sanitize user-generated content before rendering it in the DOM.
Warning: Never rely solely on client-side sanitization. Server-side validation is also critical.
8. Implementing Certificate Pinning
Certificate pinning is a security technique used to ensure that an application only accepts a specific certificate or set of certificates from a server. This helps prevent man-in-the-middle (MITM) attacks by ensuring that the application only communicates with servers that present a trusted certificate.
| Property | Description | Value |
|---|---|---|
| certificatePinning | Enables or disables certificate pinning for the application. | true or false |
| allowedCertificates | List of SHA-256 hashes of the allowed certificates. | Array of strings |
| bypassOnDebug | Allows bypassing certificate pinning in debug mode. | true or false |
Example: Configuring Certificate Pinning in Ionic
const config = {
certificatePinning: true,
allowedCertificates: [
'a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890',
'f0e9d8c7b6a59483726150493827160594837261504938271605948372615049'
],
bypassOnDebug: true
};
Note: The certificate hashes must be SHA-256 encoded. Ensure that the certificates used in production match these hashes exactly.
Warning: Disabling certificate pinning in production environments can expose your application to security risks. Only disable it for debugging purposes.
9. Using Encrypted Storage
| Storage Type | Description | Encryption | Usage Example |
|---|---|---|---|
| Secure Storage | Platform-specific secure storage for sensitive data | NEW AES-256 encryption | |
| SQLite Encryption | Encrypted local database using SQLCipher | AES-256 with salted keys | |
| Keychain (iOS) | Secure storage using iOS Keychain Services | NEW AES-256 + hardware-backed | |
Example: Securely Storing API Tokens
import { SecureStoragePlugin } from '@ionic-native/secure-storage';
const storage = new SecureStoragePlugin();
// Store token securely
await storage.create('auth');
await storage.set('apiToken', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...');
// Retrieve token
const token = await storage.get('apiToken');
console.log(token);
Note: Always use secure storage for sensitive data like tokens, passwords, or keys. Never store them in plain text or local storage.
10. Validating API Responses
| Property | Description | Example |
|---|---|---|
| response.status | HTTP status code returned by the API | 200, 404, 500 |
| response.body | JSON or XML payload from the API | |
| response.headers | Metadata about the response | Content-Type: application/json |
Example: Validate API Response in Ionic
import { HttpClient } from '@angular/common/http';
interface ApiResponse {
id: number;
name: string;
}
const validateResponse = (response: ApiResponse): boolean => {
return response.id && typeof response.name === 'string';
};
this.http.get<ApiResponse>('/api/app').subscribe({
next: (res) => {
if (validateResponse(res)) {
console.log('Valid response received');
} else {
console.error('Invalid response format');
}
},
error: (err) => console.error('API Error', err)
});
Note: Always validate API responses to prevent runtime errors and ensure data integrity.
Warning: Never trust external API responses without validation, especially when used in UI rendering or business logic.