Usamos cookies para mejorar tu experiencia en el sitio
CodeWorlds

Kompleksowe Security Practices w React

Bezpieczeństwo aplikacji React to kluczowy aspekt nowoczesnego rozwoju oprogramowania. W tej lekcji poznamy kompleksowe praktyki bezpieczeństwa, począwszy od podstawowych zabezpieczeń przed XSS, aż po zaawansowane techniki ochrony zgodne z OWASP Top 10.

1. Cross-Site Scripting (XSS) Protection

Automatyczne escapowanie w React

React domyślnie chroni przed XSS poprzez automatyczne escapowanie:

1// React automatycznie escapuje te wartości
2function UserProfile({ userData }) {
3  return (
4    <div>
5      {/* Bezpieczne - React escapuje zawartość */}
6      <h1>{userData.name}</h1>
7      <p>{userData.description}</p>
8      
9      {/* NIEBEZPIECZNE - omija escapowanie */}
10      <div dangerouslySetInnerHTML={{ __html: userData.bio }} />
11    </div>
12  );
13}

Zabezpieczenie przed XSS w różnych kontekstach

1// Bezpieczne komponenty z walidacją
2function SafeHTMLRenderer({ content, allowedTags = [] }) {
3  // Biblioteka DOMPurify do oczyszczania HTML
4  const cleanHTML = DOMPurify.sanitize(content, {
5    ALLOWED_TAGS: allowedTags,
6    ALLOWED_ATTR: ['href', 'title', 'alt', 'src'],
7    ALLOW_DATA_ATTR: false
8  });
9  
10  return (
11    <div dangerouslySetInnerHTML={{ __html: cleanHTML }} />
12  );
13}
14
15// Walidacja URL-i
16function SafeLink({ href, children, ...props }) {
17  const isValidURL = (url) => {
18    try {
19      const urlObj = new URL(url);
20      // Zezwalaj tylko na bezpieczne protokoły
21      return ['http:', 'https:', 'mailto:'].includes(urlObj.protocol);
22    } catch {
23      return false;
24    }
25  };
26  
27  if (!isValidURL(href)) {
28    console.warn('Niebezpieczny URL zablokowany:', href);
29    return <span>{children}</span>;
30  }
31  
32  return (
33    <a 
34      href={href} 
35      {...props}
36      rel="noopener noreferrer" // Zabezpieczenie przed tabnabbing
37    >
38      {children}
39    </a>
40  );
41}
42
43// Bezpieczne renderowanie obrazów
44function SafeImage({ src, alt, ...props }) {
45  const [imageSrc, setImageSrc] = useState(null);
46  const [error, setError] = useState(false);
47  
48  useEffect(() => {
49    // Walidacja źródła obrazu
50    if (src && typeof src === 'string') {
51      try {
52        const url = new URL(src);
53        if (['http:', 'https:', 'data:'].includes(url.protocol)) {
54          setImageSrc(src);
55        } else {
56          setError(true);
57        }
58      } catch {
59        setError(true);
60      }
61    }
62  }, [src]);
63  
64  if (error) {
65    return <div className="image-error">Nieprawidłowe źródło obrazu</div>;
66  }
67  
68  return imageSrc ? (
69    <img 
70      src={imageSrc} 
71      alt={alt} 
72      {...props}
73      onError={() => setError(true)}
74    />
75  ) : null;
76}

Content Security Policy (CSP) - implementacja

1// CSP Header configuration
2const cspConfig = {
3  'default-src': ["'self'"],
4  'script-src': [
5    "'self'",
6    "'unsafe-inline'", // Tylko w development
7    'https://apis.google.com',
8    'https://cdn.jsdelivr.net'
9  ],
10  'style-src': [
11    "'self'",
12    "'unsafe-inline'", // Dla CSS-in-JS
13    'https://fonts.googleapis.com'
14  ],
15  'img-src': [
16    "'self'",
17    'data:',
18    'https:',
19    'blob:'
20  ],
21  'font-src': [
22    "'self'",
23    'https://fonts.gstatic.com'
24  ],
25  'connect-src': [
26    "'self'",
27    'https://api.example.com',
28    'wss://socket.example.com'
29  ],
30  'frame-ancestors': ["'none'"],
31  'form-action': ["'self'"],
32  'upgrade-insecure-requests': []
33};
34
35// Next.js CSP configuration
36// next.config.js
37const securityHeaders = [
38  {
39    key: 'Content-Security-Policy',
40    value: Object.entries(cspConfig)
41      .map(([directive, sources]) => 
42        `${directive} ${sources.join(' ')}`
43      )
44      .join('; ')
45  },
46  {
47    key: 'X-Frame-Options',
48    value: 'DENY'
49  },
50  {
51    key: 'X-Content-Type-Options',
52    value: 'nosniff'
53  },
54  {
55    key: 'Referrer-Policy',
56    value: 'strict-origin-when-cross-origin'
57  },
58  {
59    key: 'Permissions-Policy',
60    value: 'camera=(), microphone=(), geolocation=()'
61  }
62];
63
64module.exports = {
65  async headers() {
66    return [
67      {
68        source: '/(.*)',
69        headers: securityHeaders
70      }
71    ];
72  }
73};

2. JWT Security

Bezpieczne zarządzanie tokenami

1// Secure JWT storage and handling
2class SecureTokenManager {
3  constructor() {
4    this.tokenKey = 'auth_token';
5    this.refreshTokenKey = 'refresh_token';
6  }
7  
8  // Przechowywanie w httpOnly cookies (najlepsze)
9  setTokens(accessToken, refreshToken) {
10    // Wysyłanie na backend do ustawienia httpOnly cookies
11    fetch('/api/auth/set-tokens', {
12      method: 'POST',
13      headers: { 'Content-Type': 'application/json' },
14      body: JSON.stringify({ accessToken, refreshToken })
15    });
16  }
17  
18  // Alternatywnie - sessionStorage (mniej bezpieczne)
19  setTokensInStorage(accessToken, refreshToken) {
20    // NIGDY nie używaj localStorage dla tokenów!
21    sessionStorage.setItem(this.tokenKey, accessToken);
22    
23    if (refreshToken) {
24      // Refresh token w bezpiecznym miejscu
25      this.storeRefreshTokenSecurely(refreshToken);
26    }
27  }
28  
29  getToken() {
30    return sessionStorage.getItem(this.tokenKey);
31  }
32  
33  removeTokens() {
34    sessionStorage.removeItem(this.tokenKey);
35    sessionStorage.removeItem(this.refreshTokenKey);
36    
37    // Wyloguj także z cookies
38    fetch('/api/auth/logout', { method: 'POST' });
39  }
40  
41  // Walidacja tokenu
42  isTokenValid(token) {
43    if (!token) return false;
44    
45    try {
46      const payload = JSON.parse(atob(token.split('.')[1]));
47      const now = Date.now() / 1000;
48      
49      // Sprawdź czy token nie wygasł
50      return payload.exp > now;
51    } catch {
52      return false;
53    }
54  }
55  
56  // Automatyczne odświeżanie tokenu
57  async refreshTokenIfNeeded() {
58    const token = this.getToken();
59    
60    if (!token || !this.isTokenValid(token)) {
61      return await this.refreshToken();
62    }
63    
64    return token;
65  }
66  
67  async refreshToken() {
68    try {
69      const response = await fetch('/api/auth/refresh', {
70        method: 'POST',
71        credentials: 'include' // Dla httpOnly cookies
72      });
73      
74      if (response.ok) {
75        const { accessToken } = await response.json();
76        sessionStorage.setItem(this.tokenKey, accessToken);
77        return accessToken;
78      }
79    } catch (error) {
80      console.error('Token refresh failed:', error);
81      this.removeTokens();
82    }
83    
84    return null;
85  }
86}
87
88// Hook dla autoryzacji
89function useAuth() {
90  const [user, setUser] = useState(null);
91  const [loading, setLoading] = useState(true);
92  const tokenManager = useRef(new SecureTokenManager());
93  
94  const login = async (credentials) => {
95    try {
96      const response = await fetch('/api/auth/login', {
97        method: 'POST',
98        headers: { 'Content-Type': 'application/json' },
99        body: JSON.stringify(credentials)
100      });
101      
102      if (response.ok) {
103        const { user, accessToken, refreshToken } = await response.json();
104        
105        // Bezpieczne przechowywanie tokenów
106        tokenManager.current.setTokens(accessToken, refreshToken);
107        setUser(user);
108        
109        return { success: true };
110      }
111    } catch (error) {
112      return { success: false, error: error.message };
113    }
114  };
115  
116  const logout = () => {
117    tokenManager.current.removeTokens();
118    setUser(null);
119  };
120  
121  // Automatyczne odświeżanie tokenu
122  useEffect(() => {
123    const interval = setInterval(async () => {
124      await tokenManager.current.refreshTokenIfNeeded();
125    }, 5 * 60 * 1000); // Co 5 minut
126    
127    return () => clearInterval(interval);
128  }, []);
129  
130  return { user, login, logout, loading };
131}

Axios interceptors z JWT

1// Secure Axios configuration
2const createSecureAxiosInstance = () => {
3  const tokenManager = new SecureTokenManager();
4  
5  const axiosInstance = axios.create({
6    baseURL: process.env.REACT_APP_API_URL,
7    timeout: 10000,
8    withCredentials: true // Dla httpOnly cookies
9  });
10  
11  // Request interceptor
12  axiosInstance.interceptors.request.use(
13    async (config) => {
14      const token = await tokenManager.refreshTokenIfNeeded();
15      
16      if (token) {
17        config.headers.Authorization = `Bearer ${token}`;
18      }
19      
20      // Dodaj CSRF token jeśli dostępny
21      const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content;
22      if (csrfToken) {
23        config.headers['X-CSRF-Token'] = csrfToken;
24      }
25      
26      return config;
27    },
28    (error) => Promise.reject(error)
29  );
30  
31  // Response interceptor
32  axiosInstance.interceptors.response.use(
33    (response) => response,
34    async (error) => {
35      const originalRequest = error.config;
36      
37      if (error.response?.status === 401 && !originalRequest._retry) {
38        originalRequest._retry = true;
39        
40        const newToken = await tokenManager.refreshToken();
41        
42        if (newToken) {
43          originalRequest.headers.Authorization = `Bearer ${newToken}`;
44          return axiosInstance(originalRequest);
45        } else {
46          // Przekieruj do logowania
47          window.location.href = '/login';
48        }
49      }
50      
51      return Promise.reject(error);
52    }
53  );
54  
55  return axiosInstance;
56};

3. Environment Variables Security

Bezpieczne zarządzanie zmiennymi środowiskowymi

1// .env.example - template dla zespołu
2REACT_APP_API_URL=https://api.example.com
3REACT_APP_ENVIRONMENT=development
4REACT_APP_SENTRY_DSN=your_sentry_dsn_here
5
6# Sekrety (NIE DODAWAJ do .env.example)
7# API_SECRET_KEY=your_secret_here
8# DATABASE_URL=your_db_url_here
1// Walidacja zmiennych środowiskowych
2class EnvironmentValidator {
3  static requiredVars = [
4    'REACT_APP_API_URL',
5    'REACT_APP_ENVIRONMENT'
6  ];
7  
8  static validate() {
9    const missing = this.requiredVars.filter(
10      varName => !process.env[varName]
11    );
12    
13    if (missing.length > 0) {
14      throw new Error(
15        `Missing required environment variables: ${missing.join(', ')}`
16      );
17    }
18  }
19  
20  static get(key, defaultValue = null) {
21    const value = process.env[key];
22    
23    if (!value && defaultValue === null) {
24      console.warn(`Environment variable ${key} is not set`);
25    }
26    
27    return value || defaultValue;
28  }
29  
30  static getSecure(key) {
31    const value = process.env[key];
32    
33    if (!value) {
34      throw new Error(`Secure environment variable ${key} is required`);
35    }
36    
37    return value;
38  }
39}
40
41// Konfiguracja aplikacji
42const appConfig = {
43  apiUrl: EnvironmentValidator.getSecure('REACT_APP_API_URL'),
44  environment: EnvironmentValidator.get('REACT_APP_ENVIRONMENT', 'development'),
45  isDevelopment: process.env.NODE_ENV === 'development',
46  isProduction: process.env.NODE_ENV === 'production',
47  
48  // Funkcje pomocnicze
49  get isSecure() {
50    return this.apiUrl.startsWith('https://');
51  },
52  
53  get shouldEnableDevTools() {
54    return this.isDevelopment && !this.isProduction;
55  }
56};
57
58// Walidacja przy starcie aplikacji
59EnvironmentValidator.validate();

Bezpieczna konfiguracja dla różnych środowisk

1// ConfigProvider.jsx
2const ConfigContext = createContext();
3
4export function ConfigProvider({ children }) {
5  const config = useMemo(() => {
6    const baseConfig = {
7      apiUrl: process.env.REACT_APP_API_URL,
8      environment: process.env.REACT_APP_ENVIRONMENT,
9      version: process.env.REACT_APP_VERSION || '1.0.0'
10    };
11    
12    // Konfiguracja specyficzna dla środowiska
13    const environmentConfigs = {
14      development: {
15        debug: true,
16        logLevel: 'debug',
17        enableMocks: true
18      },
19      staging: {
20        debug: true,
21        logLevel: 'info',
22        enableMocks: false
23      },
24      production: {
25        debug: false,
26        logLevel: 'error',
27        enableMocks: false
28      }
29    };
30    
31    return {
32      ...baseConfig,
33      ...environmentConfigs[baseConfig.environment] || environmentConfigs.production
34    };
35  }, []);
36  
37  return (
38    <ConfigContext.Provider value={config}>
39      {children}
40    </ConfigContext.Provider>
41  );
42}
43
44export const useConfig = () => {
45  const context = useContext(ConfigContext);
46  if (!context) {
47    throw new Error('useConfig must be used within ConfigProvider');
48  }
49  return context;
50};

4. Dependency Scanning i Supply Chain Security

Automatyczne skanowanie zależności

1// package.json scripts dla security
2{
3  "scripts": {
4    "audit": "npm audit",
5    "audit:fix": "npm audit fix",
6    "audit:force": "npm audit fix --force",
7    "security:check": "npm audit && npm run license:check",
8    "license:check": "license-checker --summary",
9    "deps:update": "npm-check-updates -u",
10    "deps:check": "npm outdated"
11  },
12  "devDependencies": {
13    "license-checker": "^25.0.1",
14    "npm-check-updates": "^16.0.0",
15    "audit-ci": "^6.6.1"
16  }
17}

CI/CD Security Pipeline

1# .github/workflows/security.yml
2name: Security Checks
3
4on: [push, pull_request]
5
6jobs:
7  security:
8    runs-on: ubuntu-latest
9    
10    steps:
11      - uses: actions/checkout@v3
12      
13      - name: Setup Node.js
14        uses: actions/setup-node@v3
15        with:
16          node-version: '18'
17          cache: 'npm'
18      
19      - name: Install dependencies
20        run: npm ci
21      
22      - name: Run npm audit
23        run: npm audit --audit-level high
24      
25      - name: Check for known vulnerabilities
26        run: npx audit-ci --high
27      
28      - name: License compliance check
29        run: npm run license:check
30      
31      - name: SAST with CodeQL
32        uses: github/codeql-action/analyze@v2
33        with:
34          languages: javascript
35      
36      - name: Dependency Review
37        uses: actions/dependency-review-action@v3
38        if: github.event_name == 'pull_request'

Runtime Security Monitoring

1// SecurityMonitor.jsx
2class SecurityMonitor {
3  constructor() {
4    this.violations = [];
5    this.init();
6  }
7  
8  init() {
9    // Monitorowanie CSP violations
10    document.addEventListener('securitypolicyviolation', (e) => {
11      this.reportViolation({
12        type: 'CSP_VIOLATION',
13        directive: e.violatedDirective,
14        blockedURI: e.blockedURI,
15        documentURI: e.documentURI,
16        timestamp: new Date().toISOString()
17      });
18    });
19    
20    // Monitorowanie console.error dla potencjalnych problemów bezpieczeństwa
21    const originalError = console.error;
22    console.error = (...args) => {
23      const message = args.join(' ');
24      
25      if (this.isSecurityRelated(message)) {
26        this.reportViolation({
27          type: 'SECURITY_ERROR',
28          message,
29          timestamp: new Date().toISOString()
30        });
31      }
32      
33      originalError.apply(console, args);
34    };
35  }
36  
37  isSecurityRelated(message) {
38    const securityKeywords = [
39      'unsafe-inline',
40      'unsafe-eval',
41      'xss',
42      'csrf',
43      'cors',
44      'unauthorized',
45      'forbidden'
46    ];
47    
48    return securityKeywords.some(keyword => 
49      message.toLowerCase().includes(keyword)
50    );
51  }
52  
53  reportViolation(violation) {
54    this.violations.push(violation);
55    
56    // Wyślij do systemu monitorowania
57    if (process.env.NODE_ENV === 'production') {
58      fetch('/api/security/violations', {
59        method: 'POST',
60        headers: { 'Content-Type': 'application/json' },
61        body: JSON.stringify(violation)
62      }).catch(error => {
63        console.error('Failed to report security violation:', error);
64      });
65    }
66  }
67  
68  getViolations() {
69    return [...this.violations];
70  }
71}
72
73// Hook dla monitorowania bezpieczeństwa
74export function useSecurityMonitor() {
75  const monitor = useRef(new SecurityMonitor());
76  
77  const reportCustomViolation = useCallback((violation) => {
78    monitor.current.reportViolation({
79      type: 'CUSTOM_VIOLATION',
80      ...violation,
81      timestamp: new Date().toISOString()
82    });
83  }, []);
84  
85  return {
86    reportViolation: reportCustomViolation,
87    getViolations: () => monitor.current.getViolations()
88  };
89}

5. Input Validation & Sanitization

Kompleksowa walidacja danych wejściowych

1// InputValidator.js
2class InputValidator {
3  static patterns = {
4    email: /^[^s@]+@[^s@]+.[^s@]+$/,
5    phone: /^+?[ds-()]+$/,
6    url: /^https?://.+/,
7    alphanumeric: /^[a-zA-Z0-9]+$/,
8    noSpecialChars: /^[a-zA-Z0-9s-_]+$/
9  };
10  
11  static validate(value, rules) {
12    const errors = [];
13    
14    // Required validation
15    if (rules.required && (!value || value.trim() === '')) {
16      errors.push('This field is required');
17    }
18    
19    if (!value) return errors;
20    
21    // Length validation
22    if (rules.minLength && value.length < rules.minLength) {
23      errors.push(`Minimum length is ${rules.minLength} characters`);
24    }
25    
26    if (rules.maxLength && value.length > rules.maxLength) {
27      errors.push(`Maximum length is ${rules.maxLength} characters`);
28    }
29    
30    // Pattern validation
31    if (rules.pattern && !this.patterns[rules.pattern]?.test(value)) {
32      errors.push(`Invalid ${rules.pattern} format`);
33    }
34    
35    // Custom validation
36    if (rules.custom) {
37      const customError = rules.custom(value);
38      if (customError) errors.push(customError);
39    }
40    
41    // XSS prevention
42    if (rules.preventXSS && this.containsPotentialXSS(value)) {
43      errors.push('Input contains potentially dangerous content');
44    }
45    
46    return errors;
47  }
48  
49  static containsPotentialXSS(value) {
50    const xssPatterns = [
51      /<script[^>]*>.*?</script>/gi,
52      /javascript:/gi,
53      /onw+s*=/gi,
54      /<iframe[^>]*>/gi,
55      /<object[^>]*>/gi,
56      /<embed[^>]*>/gi,
57      /evals*(/gi,
58      /expressions*(/gi
59    ];
60    
61    return xssPatterns.some(pattern => pattern.test(value));
62  }
63  
64  static sanitize(value, options = {}) {
65    if (!value) return value;
66    
67    let sanitized = value;
68    
69    // Remove HTML tags
70    if (options.stripHTML) {
71      sanitized = sanitized.replace(/<[^>]*>/g, '');
72    }
73    
74    // Escape HTML entities
75    if (options.escapeHTML) {
76      sanitized = sanitized
77        .replace(/&/g, '&amp;')
78        .replace(/</g, '&lt;')
79        .replace(/>/g, '&gt;')
80        .replace(/"/g, '&quot;')
81        .replace(/'/g, '&#x27;');
82    }
83    
84    // Remove null bytes
85    sanitized = sanitized.replace(//g, '');
86    
87    // Trim whitespace
88    if (options.trim !== false) {
89      sanitized = sanitized.trim();
90    }
91    
92    return sanitized;
93  }
94}
95
96// SecureForm component
97function SecureForm({ onSubmit, children }) {
98  const [formData, setFormData] = useState({});
99  const [errors, setErrors] = useState({});
100  const [isSubmitting, setIsSubmitting] = useState(false);
101  
102  const validateField = useCallback((name, value, rules) => {
103    const fieldErrors = InputValidator.validate(value, rules);
104    
105    setErrors(prev => ({
106      ...prev,
107      [name]: fieldErrors.length > 0 ? fieldErrors : undefined
108    }));
109    
110    return fieldErrors.length === 0;
111  }, []);
112  
113  const handleInputChange = useCallback((name, value, rules) => {
114    // Sanitize input
115    const sanitizedValue = InputValidator.sanitize(value, {
116      stripHTML: true,
117      escapeHTML: true,
118      trim: true
119    });
120    
121    setFormData(prev => ({
122      ...prev,
123      [name]: sanitizedValue
124    }));
125    
126    // Validate on change
127    validateField(name, sanitizedValue, rules);
128  }, [validateField]);
129  
130  const handleSubmit = async (e, validationRules) => {
131    e.preventDefault();
132    setIsSubmitting(true);
133    
134    // Validate all fields
135    let isValid = true;
136    const newErrors = {};
137    
138    Object.entries(validationRules).forEach(([fieldName, rules]) => {
139      const fieldValue = formData[fieldName];
140      const fieldErrors = InputValidator.validate(fieldValue, rules);
141      
142      if (fieldErrors.length > 0) {
143        newErrors[fieldName] = fieldErrors;
144        isValid = false;
145      }
146    });
147    
148    setErrors(newErrors);
149    
150    if (isValid) {
151      try {
152        await onSubmit(formData);
153      } catch (error) {
154        console.error('Form submission failed:', error);
155      }
156    }
157    
158    setIsSubmitting(false);
159  };
160  
161  return (
162    <form onSubmit={handleSubmit}>
163      {React.Children.map(children, child => {
164        if (React.isValidElement(child) && child.props.name) {
165          return React.cloneElement(child, {
166            value: formData[child.props.name] || '',
167            onChange: (e) => handleInputChange(
168              child.props.name,
169              e.target.value,
170              child.props.validationRules
171            ),
172            error: errors[child.props.name],
173            disabled: isSubmitting
174          });
175        }
176        return child;
177      })}
178    </form>
179  );
180}

6. OWASP Top 10 Compliance

Implementacja zabezpieczeń według OWASP

1// OWASP Security Checklist Implementation
2
3// 1. Injection Prevention
4const SQLInjectionPrevention = {
5  // Zawsze używaj prepared statements
6  safeQuery: (query, params) => {
7    // Backend implementation example
8    return db.prepare(query).run(params);
9  },
10  
11  // Walidacja parametrów
12  validateParams: (params, schema) => {
13    return schema.validate(params);
14  }
15};
16
17// 2. Broken Authentication Prevention
18const AuthenticationSecurity = {
19  // Silne hasła
20  passwordPolicy: {
21    minLength: 12,
22    requireUppercase: true,
23    requireLowercase: true,
24    requireNumbers: true,
25    requireSpecialChars: true,
26    maxAge: 90 * 24 * 60 * 60 * 1000 // 90 dni
27  },
28  
29  // Account lockout
30  loginAttempts: {
31    maxAttempts: 5,
32    lockoutDuration: 15 * 60 * 1000 // 15 minut
33  },
34  
35  // Session management
36  sessionConfig: {
37    httpOnly: true,
38    secure: true,
39    sameSite: 'strict',
40    maxAge: 30 * 60 * 1000 // 30 minut
41  }
42};
43
44// 3. Sensitive Data Exposure Prevention
45const DataProtection = {
46  // Szyfrowanie wrażliwych danych
47  encryptSensitiveData: (data) => {
48    // Implementacja szyfrowania
49    return CryptoJS.AES.encrypt(data, process.env.ENCRYPTION_KEY);
50  },
51  
52  // Bezpieczne przechowywanie
53  secureStorage: {
54    set: (key, value) => {
55      const encrypted = DataProtection.encryptSensitiveData(value);
56      sessionStorage.setItem(key, encrypted);
57    },
58    
59    get: (key) => {
60      const encrypted = sessionStorage.getItem(key);
61      if (encrypted) {
62        const decrypted = CryptoJS.AES.decrypt(encrypted, process.env.ENCRYPTION_KEY);
63        return decrypted.toString(CryptoJS.enc.Utf8);
64      }
65      return null;
66    }
67  }
68};
69
70// 4. XML External Entities (XXE) Prevention
71const XXEPrevention = {
72  // Bezpieczne parsowanie XML
73  parseXMLSafely: (xmlString) => {
74    const parser = new DOMParser();
75    const doc = parser.parseFromString(xmlString, 'text/xml');
76    
77    // Sprawdź błędy parsowania
78    const parseError = doc.querySelector('parsererror');
79    if (parseError) {
80      throw new Error('Invalid XML format');
81    }
82    
83    return doc;
84  }
85};
86
87// 5. Broken Access Control Prevention
88function ProtectedRoute({ children, requiredRole, requiredPermissions }) {
89  const { user, hasRole, hasPermissions } = useAuth();
90  
91  if (!user) {
92    return <Redirect to="/login" />;
93  }
94  
95  if (requiredRole && !hasRole(requiredRole)) {
96    return <div>Access Denied: Insufficient role</div>;
97  }
98  
99  if (requiredPermissions && !hasPermissions(requiredPermissions)) {
100    return <div>Access Denied: Insufficient permissions</div>;
101  }
102  
103  return children;
104}
105
106// 6. Security Misconfiguration Prevention
107const SecurityConfig = {
108  // Headers bezpieczeństwa
109  securityHeaders: {
110    'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
111    'X-Content-Type-Options': 'nosniff',
112    'X-Frame-Options': 'DENY',
113    'X-XSS-Protection': '1; mode=block',
114    'Referrer-Policy': 'strict-origin-when-cross-origin'
115  },
116  
117  // Konfiguracja CORS
118  corsConfig: {
119    origin: process.env.ALLOWED_ORIGINS?.split(',') || [],
120    credentials: true,
121    optionsSuccessStatus: 200
122  }
123};

Kompleksowe praktyki bezpieczeństwa w React wymagają holistycznego podejścia, obejmującego wszystkie warstwy aplikacji - od klienta po serwer. Kluczem jest regularne audytowanie, aktualizowanie zależności i przestrzeganie najlepszych praktyk branżowych zgodnych z OWASP Top 10.

Ir a CodeWorlds