Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:25:02 +08:00
commit ec2cec7636
8 changed files with 2608 additions and 0 deletions

429
commands/audit-security.md Normal file
View File

@@ -0,0 +1,429 @@
# Audit Security Command
Comprehensive security audit for Angular applications following OWASP guidelines.
## Usage
```bash
/angular-security:audit-security
```
## Audit Categories
### 1. Dependency Vulnerabilities
```bash
# Check for vulnerable packages
npm audit
# Fix automatically
npm audit fix
# View detailed report
npm audit --json
# Check specific severity
npm audit --audit-level=high
```
### 2. XSS Vulnerabilities
```typescript
// Scan for dangerous patterns:
// - innerHTML with user data
// - bypassSecurityTrust* methods
// - [style], [href], [src] with user input
// - Dynamic script/style injection
// ❌ Found issues:
[innerHTML]="userContent" // XSS risk
[src]="untrustedUrl" // URL injection
[style]="userStyle" // Style injection
bypassSecurityTrustHtml(userHtml) // Bypassing protection
```
### 3. Authentication & Authorization
```typescript
// ✅ Secure auth implementation
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const token = inject(AuthService).getToken();
if (token) {
req = req.clone({
setHeaders: {
'Authorization': `Bearer ${token}`,
'X-Requested-With': 'XMLHttpRequest' // CSRF protection
}
});
}
return next(req).pipe(
catchError((error: HttpErrorResponse) => {
if (error.status === 401) {
inject(Router).navigate(['/login']);
}
return throwError(() => error);
})
);
};
// ✅ Secure route guard
export const authGuard: CanActivateFn = (route, state) => {
const authService = inject(AuthService);
const router = inject(Router);
if (authService.isAuthenticated()) {
// Check role-based access
const requiredRole = route.data['role'];
if (requiredRole && !authService.hasRole(requiredRole)) {
return router.parseUrl('/unauthorized');
}
return true;
}
return router.parseUrl('/login');
};
```
### 4. CSRF Protection
```typescript
// ✅ CSRF token implementation
export class CsrfInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Get CSRF token from cookie
const csrfToken = this.getCookie('XSRF-TOKEN');
// Add to header for state-changing requests
if (req.method !== 'GET' && req.method !== 'HEAD') {
req = req.clone({
setHeaders: {
'X-XSRF-TOKEN': csrfToken
}
});
}
return next.handle(req);
}
private getCookie(name: string): string {
const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
return match ? match[2] : '';
}
}
```
### 5. Token Storage
```typescript
// ❌ INSECURE: localStorage
localStorage.setItem('token', jwt); // Vulnerable to XSS
// ✅ SECURE: HttpOnly cookie (server-side)
// Set-Cookie: token=xxx; HttpOnly; Secure; SameSite=Strict
// ✅ ALTERNATIVE: Memory + refresh token
@Injectable({ providedIn: 'root' })
export class TokenService {
private accessToken: string | null = null;
setToken(token: string) {
this.accessToken = token;
// Refresh token in HttpOnly cookie
}
getToken(): string | null {
return this.accessToken;
}
clearToken() {
this.accessToken = null;
}
}
```
### 6. Input Validation
```typescript
// ✅ Comprehensive validation
export class SecureFormComponent {
form = this.fb.group({
username: ['', [
Validators.required,
Validators.minLength(3),
Validators.maxLength(20),
Validators.pattern(/^[a-zA-Z0-9_]+$/)
]],
email: ['', [
Validators.required,
Validators.email
]],
age: ['', [
Validators.required,
Validators.min(18),
Validators.max(120)
]],
website: ['', [
this.urlValidator()
]]
});
private urlValidator(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
if (!control.value) return null;
try {
const url = new URL(control.value);
// Only allow https
if (url.protocol !== 'https:') {
return { invalidProtocol: true };
}
return null;
} catch {
return { invalidUrl: true };
}
};
}
}
```
### 7. Secure HTTP Communication
```typescript
// ✅ HTTPS enforcement
export class AppComponent implements OnInit {
ngOnInit() {
// Redirect HTTP to HTTPS
if (location.protocol !== 'https:' &&
!location.hostname.includes('localhost')) {
location.replace(`https:${location.href.substring(location.protocol.length)}`);
}
}
}
// ✅ Security headers (server-side config)
// Strict-Transport-Security: max-age=31536000; includeSubDomains
// X-Content-Type-Options: nosniff
// X-Frame-Options: DENY
// X-XSS-Protection: 1; mode=block
// Referrer-Policy: strict-origin-when-cross-origin
```
### 8. Content Security Policy
```html
<!-- Strict CSP -->
<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self';
style-src 'self';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
">
```
### 9. Rate Limiting
```typescript
// ✅ Client-side rate limiting
@Injectable({ providedIn: 'root' })
export class RateLimitService {
private requests = new Map<string, number[]>();
private readonly WINDOW_MS = 60000; // 1 minute
private readonly MAX_REQUESTS = 10;
canMakeRequest(key: string): boolean {
const now = Date.now();
const timestamps = this.requests.get(key) || [];
// Remove old timestamps
const validTimestamps = timestamps.filter(ts =>
now - ts < this.WINDOW_MS
);
if (validTimestamps.length >= this.MAX_REQUESTS) {
return false;
}
validTimestamps.push(now);
this.requests.set(key, validTimestamps);
return true;
}
}
```
### 10. Logging & Monitoring
```typescript
// ✅ Security event logging
@Injectable({ providedIn: 'root' })
export class SecurityLogger {
logSecurityEvent(event: SecurityEvent) {
const log = {
timestamp: new Date().toISOString(),
event: event.type,
severity: event.severity,
user: this.authService.getCurrentUser()?.id,
details: event.details,
userAgent: navigator.userAgent,
ip: this.getClientIp()
};
// Send to security monitoring service
this.http.post('/api/security/log', log).subscribe();
}
logFailedLogin(username: string) {
this.logSecurityEvent({
type: 'FAILED_LOGIN',
severity: 'HIGH',
details: { username }
});
}
logXSSAttempt(payload: string) {
this.logSecurityEvent({
type: 'XSS_ATTEMPT',
severity: 'CRITICAL',
details: { payload }
});
}
}
```
## Audit Report Example
```
🔒 Security Audit Report
Generated: 2025-10-21 15:30:00
┌─────────────────────────────────────────┐
│ OWASP Top 10 Compliance │
├─────────────────────────────────────────┤
│ A01: Broken Access Control ✅ PASS │
│ A02: Cryptographic Failures ✅ PASS │
│ A03: Injection ⚠️ WARN │
│ A04: Insecure Design ✅ PASS │
│ A05: Security Misconfiguration ❌ FAIL │
│ A06: Vulnerable Components ⚠️ WARN │
│ A07: Auth Failures ✅ PASS │
│ A08: Software/Data Integrity ✅ PASS │
│ A09: Logging Failures ⚠️ WARN │
│ A10: Server-Side Forgery ✅ PASS │
└─────────────────────────────────────────┘
📊 Severity Breakdown:
┌──────────┬───────┬──────────────────┐
│ Severity │ Count │ Issues │
├──────────┼───────┼──────────────────┤
│ 🔴 CRITICAL │ 0 │ │
│ 🔴 HIGH │ 2 │ XSS, CSP missing │
│ 🟡 MEDIUM │ 5 │ Various │
│ 🟢 LOW │ 3 │ Improvements │
└──────────┴───────┴──────────────────┘
🔴 HIGH Priority Issues:
1. XSS Vulnerability in UserProfileComponent
File: user-profile.component.ts:45
Code: [innerHTML]="userBio"
Fix: Use DomSanitizer or remove innerHTML
2. Missing Content-Security-Policy
File: index.html
Impact: No XSS protection layer
Fix: Add CSP meta tag
🟡 MEDIUM Priority Issues:
3. Hardcoded API credentials
File: environment.ts:8
Fix: Use environment variables
4. No rate limiting on login
File: auth.service.ts:23
Fix: Implement rate limiting
5. JWT in localStorage
File: token.service.ts:12
Fix: Use HttpOnly cookies
🟢 LOW Priority Issues:
6. Missing security headers
Fix: Configure server headers
7. No input sanitization
Fix: Add validation to forms
8. Console.log in production
Fix: Remove debug logs
📋 npm audit Results:
┌──────────┬───────┐
│ Critical │ 0 │
│ High │ 1 │
│ Moderate │ 3 │
│ Low │ 8 │
└──────────┴───────┘
Vulnerable packages:
- lodash@4.17.15 (HIGH) → Update to 4.17.21
- axios@0.21.1 (MODERATE) → Update to 1.6.0
✅ Secure Practices Found:
- HTTPS enforced
- Route guards implemented
- Form validation present
- CSRF tokens in use
- Password hashing (bcrypt)
🎯 Security Score: 7.2/10
📈 After Fixes: 9.5/10
⏱️ Estimated Fix Time: 4-6 hours
🔧 Action Plan:
1. Fix XSS vulnerability (30 min)
2. Add CSP headers (15 min)
3. Move JWT to HttpOnly cookie (1 hour)
4. Update vulnerable dependencies (30 min)
5. Add rate limiting (1 hour)
6. Implement security logging (1 hour)
```
## Continuous Security
```yaml
# .github/workflows/security.yml
name: Security Audit
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: npm audit
run: npm audit --audit-level=moderate
- name: OWASP Dependency Check
uses: dependency-check/Dependency-Check_Action@main
- name: Snyk Security Scan
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
```
---
*Audit regularly, fix proactively! 🛡️*

View File

@@ -0,0 +1,352 @@
# Secure Component Command
Analyze and secure Angular components against XSS, injection, and other vulnerabilities.
## Usage
```bash
/angular-security:secure-component <ComponentName>
```
## Security Checks
### 1. XSS Prevention
```typescript
// ❌ CRITICAL: XSS vulnerability
@Component({
template: `<div [innerHTML]="userInput"></div>`
})
export class UnsafeComponent {
@Input() userInput: string;
}
// ✅ SECURE: Sanitized HTML
@Component({
template: `<div [innerHTML]="safeContent"></div>`
})
export class SafeComponent {
@Input() set userInput(value: string) {
this.safeContent = this.sanitizer.sanitize(
SecurityContext.HTML,
value
);
}
safeContent: SafeHtml;
constructor(private sanitizer: DomSanitizer) {}
}
// ✅ BEST: Avoid innerHTML
@Component({
template: `<div>{{ userInput }}</div>` // Auto-escaped
})
export class BestComponent {
@Input() userInput: string;
}
```
### 2. URL Sanitization
```typescript
// ❌ DANGEROUS: Arbitrary URL
<a [href]="userUrl">Click</a>
// ✅ SECURE: Sanitize URLs
export class LinkComponent {
@Input() set url(value: string) {
this.safeUrl = this.sanitizer.sanitize(
SecurityContext.URL,
value
);
}
safeUrl: SafeUrl;
constructor(private sanitizer: DomSanitizer) {}
}
// Template
<a [href]="safeUrl">Click</a>
```
### 3. Resource URL Validation
```typescript
// ❌ DANGEROUS: Untrusted resource
<iframe [src]="videoUrl"></iframe>
// ✅ SECURE: Whitelist trusted domains
export class VideoComponent {
@Input() set videoUrl(url: string) {
if (this.isTrustedDomain(url)) {
this.safeUrl = this.sanitizer.bypassSecurityTrustResourceUrl(url);
} else {
console.error('Untrusted video URL:', url);
this.safeUrl = null;
}
}
safeUrl: SafeResourceUrl | null;
private trustedDomains = ['youtube.com', 'vimeo.com'];
private isTrustedDomain(url: string): boolean {
try {
const domain = new URL(url).hostname;
return this.trustedDomains.some(trusted =>
domain.includes(trusted)
);
} catch {
return false;
}
}
constructor(private sanitizer: DomSanitizer) {}
}
```
### 4. Style Injection
```typescript
// ❌ DANGEROUS: User-controlled styles
<div [style]="userStyle">Content</div>
// ✅ SECURE: Sanitize styles
export class StyledComponent {
@Input() set userStyle(value: string) {
this.safeStyle = this.sanitizer.sanitize(
SecurityContext.STYLE,
value
);
}
safeStyle: SafeStyle;
constructor(private sanitizer: DomSanitizer) {}
}
// ✅ BETTER: Use class binding
<div [class]="userClass">Content</div>
```
### 5. Dynamic Script Loading
```typescript
// ❌ NEVER DO THIS
eval(userCode);
new Function(userCode)();
// ✅ SECURE: No dynamic code execution
// Use configuration objects instead
export class ConfigurableComponent {
@Input() config: {
enabled: boolean;
options: string[];
};
executeAction() {
// Safe configuration-driven logic
if (this.config.enabled) {
this.config.options.forEach(opt => this.handleOption(opt));
}
}
}
```
### 6. Form Input Validation
```typescript
// ✅ SECURE: Comprehensive validation
export class UserFormComponent {
userForm = this.fb.group({
username: ['', [
Validators.required,
Validators.minLength(3),
Validators.maxLength(20),
Validators.pattern(/^[a-zA-Z0-9_]+$/) // Alphanumeric only
]],
email: ['', [
Validators.required,
Validators.email
]],
bio: ['', [
Validators.maxLength(500)
]]
});
constructor(private fb: FormBuilder) {}
onSubmit() {
if (this.userForm.valid) {
// Server-side validation still required!
const data = this.userForm.value;
this.api.createUser(data).subscribe();
}
}
}
```
### 7. File Upload Security
```typescript
// ✅ SECURE: File validation
export class FileUploadComponent {
private readonly MAX_SIZE = 5 * 1024 * 1024; // 5MB
private readonly ALLOWED_TYPES = [
'image/jpeg',
'image/png',
'image/gif',
'application/pdf'
];
onFileSelected(event: Event) {
const input = event.target as HTMLInputElement;
const file = input.files?.[0];
if (!file) return;
// Validate file type
if (!this.ALLOWED_TYPES.includes(file.type)) {
alert('Invalid file type');
return;
}
// Validate file size
if (file.size > this.MAX_SIZE) {
alert('File too large (max 5MB)');
return;
}
// Validate file extension
const ext = file.name.split('.').pop()?.toLowerCase();
const validExtensions = ['jpg', 'jpeg', 'png', 'gif', 'pdf'];
if (!ext || !validExtensions.includes(ext)) {
alert('Invalid file extension');
return;
}
this.uploadFile(file);
}
}
```
### 8. Sensitive Data in Templates
```typescript
// ❌ DANGEROUS: Exposing sensitive data
@Component({
template: `
<div>API Key: {{ apiKey }}</div>
<div>Password: {{ password }}</div>
`
})
// ✅ SECURE: Never expose sensitive data
@Component({
template: `
<div>Status: {{ isAuthenticated ? 'Connected' : 'Disconnected' }}</div>
`
})
export class SecureComponent {
isAuthenticated: boolean;
// Sensitive data only in memory, never in template
private apiKey: string;
private password: string;
}
```
### 9. Clickjacking Prevention
```typescript
// Set X-Frame-Options header (server-side)
// But also check in Angular:
export class FrameGuard implements OnInit {
ngOnInit() {
// Prevent loading in iframe
if (window.self !== window.top) {
console.error('Clickjacking attempt detected');
window.top.location = window.self.location;
}
}
}
```
### 10. Content Security Policy
```html
<!-- index.html -->
<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:;
font-src 'self' data:;
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
">
```
## Security Audit Checklist
```typescript
// Component security audit
export class AuditedComponent {
// ✅ 1. No innerHTML with user data
// ✅ 2. All URLs sanitized
// ✅ 3. Form inputs validated
// ✅ 4. No eval or Function constructor
// ✅ 5. Sensitive data not in template
// ✅ 6. File uploads validated
// ✅ 7. External resources whitelisted
// ✅ 8. CSP headers configured
// ✅ 9. HTTPS enforced
// ✅ 10. Dependencies audited
}
```
## Output Example
```
🔒 Security Audit: UserProfileComponent
⚠️ Issues Found:
1. 🔴 CRITICAL: XSS Vulnerability (Line 23)
Location: template: `<div [innerHTML]="bio"></div>`
Risk: Arbitrary JavaScript execution
Fix: Use sanitizer or remove innerHTML
2. 🟡 HIGH: Unvalidated File Upload (Line 45)
Location: onFileUpload(event)
Risk: Malicious file upload
Fix: Add file type and size validation
3. 🟡 MEDIUM: Hardcoded API Key (Line 12)
Location: apiKey = 'sk_live_123...'
Risk: Credential exposure
Fix: Use environment variables
✅ Secure Patterns Detected:
- Form validation with Validators
- HTTPS enforced
- HttpOnly cookies for auth token
📋 Recommendations:
1. Sanitize HTML content
2. Validate file uploads
3. Move API key to environment config
4. Add CSP headers
5. Implement rate limiting for API calls
🎯 Security Score: 6/10 (Medium Risk)
After fixes: 9/10 (Low Risk)
```
---
*Secure every component! 🛡️*