用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/diegosouzapw/awesome-omni-skill --skill security-patterns命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | security-patterns |
| description | Zero-trust security patterns for frontend and backend |
| triggers | ["security","auth","authentication","authorization","token","XSS","OWASP"] |
Enforce zero-trust security across frontend and backend.
Automatically activate when:
Never Trust, Always Verify, Least Privilege
// ✅ CORRECT - Store in memory
@Injectable({ providedIn: 'root' })
export class AuthService {
private accessToken = signal<string | null>(null);
private refreshToken = signal<string | null>(null);
setTokens(access: string, refresh: string) {
this.accessToken.set(access);
this.refreshToken.set(refresh);
}
clearTokens() {
this.accessToken.set(null);
this.refreshToken.set(null);
}
}
// ❌ WRONG - Never use localStorage
localStorage.setItem('token', token); // FORBIDDEN
sessionStorage.setItem('token', token); // FORBIDDEN
// ✅ Use Angular's built-in sanitization
import { DomSanitizer } from '@angular/platform-browser';
@Component({...})
class SafeComponent {
private sanitizer = inject(DomSanitizer);
// Only when absolutely necessary
trustedHtml = this.sanitizer.bypassSecurityTrustHtml(userContent);
}
// ❌ WRONG - Never bypass without sanitization
[innerHTML]="userContent" // DANGEROUS
@Injectable({ providedIn: 'root' })
export class InactivityService {
private readonly TIMEOUT_MS = 15 * 60 * 1000; // 15 minutes
private timeoutId?: number;
resetTimer() {
clearTimeout(this.timeoutId);
this.timeoutId = window.setTimeout(() => this.logout(), this.TIMEOUT_MS);
}
private logout() {
this.authService.clearTokens();
this.router.navigate(['/login']);
}
}
logout() {
// Clear all sensitive data
this.accessToken.set(null);
this.refreshToken.set(null);
this.userProfile.set(null);
// Clear IndexedDB
await this.indexedDb.clear();
// Clear service worker cache
if ('serviceWorker' in navigator) {
const caches = await window.caches.keys();
await Promise.all(caches.map(c => window.caches.delete(c)));
}
}
@RestController
@RequestMapping("/api/v1/learners")
@RequiredArgsConstructor
public class LearnerController {
@GetMapping
@PreAuthorize("hasAnyRole('TEACHER', 'ADMIN')")
public List<LearnerResponse> listLearners() { ... }
@PostMapping
@PreAuthorize("hasRole('ADMIN')")
public LearnerResponse createLearner(@Valid @RequestBody request) { ... }
@DeleteMapping("/{id}")
@PreAuthorize("hasRole('SUPER_ADMIN')")
public void deleteLearner(@PathVariable UUID id) { ... }
}
public record LearnerResponse(
UUID id,
@JsonSerialize(using = MaskedStringSerializer.class)
String lrn, // Returns: "****8901"
String firstName,
@JsonSerialize(using = MaskedStringSerializer.class)
String birthDate // Returns: "****-**-15"
) {}
@Aspect
@Component
public class AuditAspect {
@Around("@annotation(Auditable)")
public Object audit(ProceedingJoinPoint pjp) throws Throwable {
AuditLog log = AuditLog.builder()
.userId(SecurityContextHolder.getContext().getUserId())
.tenantId(TenantContext.getTenantId())
.action(pjp.getSignature().getName())
.timestamp(Instant.now())
.build();
try {
Object result = pjp.proceed();
log.setStatus("SUCCESS");
return result;
} catch (Exception e) {
log.setStatus("FAILURE");
log.setError(e.getMessage());
throw e;
} finally {
auditRepository.save(log);
}
}
}
public record CreateLearnerRequest(
@NotBlank
@Size(max = 100)
@Pattern(regexp = "^[a-zA-Z\\s]+$", message = "Only letters allowed")
String firstName,
@NotNull
@Pattern(regexp = "\\d{12}", message = "LRN must be 12 digits")
String lrn,
@NotNull
@Past(message = "Birth date must be in the past")
LocalDate birthDate
) {}
1. Client generates code_verifier (random string)
2. Client creates code_challenge = SHA256(code_verifier)
3. Client redirects to /authorize?code_challenge=...
4. User authenticates
5. Server returns authorization_code
6. Client exchanges code + code_verifier for tokens
7. Server validates SHA256(code_verifier) == code_challenge
@Configuration
public class RateLimitConfig {
@Bean
public RateLimiter rateLimiter() {
return RateLimiter.of("api", RateLimiterConfig.custom()
.limitForPeriod(100) // 100 requests
.limitRefreshPeriod(Duration.ofMinutes(1))
.timeoutDuration(Duration.ofMillis(500))
.build());
}
}
-- Encrypt sensitive columns
CREATE TABLE learners (
id UUID PRIMARY KEY,
lrn TEXT, -- Stored encrypted
first_name TEXT,
birth_date DATE
);
-- Use pgcrypto for column encryption
INSERT INTO learners (id, lrn, first_name, birth_date)
VALUES (
gen_random_uuid(),
pgp_sym_encrypt('123456789012', 'encryption-key'),
'Juan',
'2010-01-15'
);
@Configuration
public class SecurityHeadersConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
return http
.headers(headers -> headers
.contentSecurityPolicy(csp -> csp
.policyDirectives("default-src 'self'; script-src 'self'"))
.frameOptions(frame -> frame.deny())
.xssProtection(xss -> xss.enable()))
.build();
}
}
@PreAuthorize on all controller methods