阿里云主机折上折
  • 微信号
Current Site:Index > CSRF protection in front-end frameworks

CSRF protection in front-end frameworks

Author:Chuan Chen 阅读数:53179人阅读 分类: 前端安全

Basic Principles of CSRF Attacks

CSRF (Cross-Site Request Forgery) is a common web security threat. When an attacker induces a user to visit a malicious website, the website sends requests to the target website where the user is authenticated, leveraging the user's logged-in status to perform unauthorized actions. This attack succeeds because the browser automatically includes authentication information such as cookies from the target website.

Typical CSRF attack flow:

  1. The user logs into a banking website, and authentication information is stored in cookies.
  2. The user visits a malicious website.
  3. The malicious website contains a request to transfer money from the bank.
  4. The browser automatically sends the request with the banking website's cookies.
  5. The bank server treats this as a legitimate request and executes the operation.
<!-- Attack code in the malicious website -->
<img src="https://bank.com/transfer?to=attacker&amount=10000" width="0" height="0">

CSRF Protection Mechanisms in Frontend Frameworks

Modern frontend frameworks provide various built-in or recommended CSRF protection solutions. These mechanisms primarily focus on verifying request origins and adding random tokens.

1. Same-Origin Policy and CORS

The browser's same-origin policy is the first line of defense against CSRF. Frontend frameworks strictly adhere to CORS specifications when handling cross-origin requests:

// Axios configuration example
axios.defaults.withCredentials = true;
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

Key configuration items:

  • withCredentials: Controls whether credentials are sent.
  • Access-Control-Allow-Origin: Specifies allowed origins.
  • Access-Control-Allow-Credentials: Determines whether cookies can be sent.

2. CSRF Token Mechanism

The mainstream framework-recommended protection involves adding CSRF tokens to forms or requests:

React Implementation Example

// Server generates and injects the token
const csrfToken = generateToken();

// Frontend component
function TransferForm() {
  return (
    <form action="/transfer" method="POST">
      <input type="hidden" name="_csrf" value={csrfToken} />
      {/* Other form fields */}
    </form>
  );
}

Vue Implementation Example

// Global interceptor setup
axios.interceptors.request.use(config => {
  config.headers['X-CSRF-TOKEN'] = getCSRFToken();
  return config;
});

3. Double Cookie Verification

Modern frameworks support enhanced protection through double cookies:

// Set HttpOnly authentication cookie
document.cookie = `auth_token=${token}; HttpOnly; Secure`;

// Also set a readable CSRF token
document.cookie = `csrf_token=${csrfToken}; SameSite=Strict`;

Framework-Specific Implementation Solutions

Angular's CSRF Protection

Angular has built-in XSRF protection, which automatically reads the XSRF-TOKEN from cookies and adds it to request headers:

// Server sets the cookie
res.cookie('XSRF-TOKEN', token, { secure: true });

// Angular handles it automatically
this.http.post('/api/transfer', data).subscribe();

React's Protection Practices

React applications often combine Redux to manage CSRF state:

// Redux store initialization
const store = createStore(reducer, {
  csrf: {
    token: window.initialData.csrfToken,
    timestamp: Date.now()
  }
});

// Higher-order component encapsulation
function withCSRF(Component) {
  return function WrappedComponent(props) {
    const csrf = useSelector(state => state.csrf);
    return <Component {...props} csrf={csrf} />;
  }
}

Vue's Solutions

The Vue ecosystem typically uses vue-resource or axios plugins:

// Vue plugin implementation
const CSRFPlugin = {
  install(Vue) {
    Vue.prototype.$csrf = {
      getToken() {
        return localStorage.getItem('csrfToken');
      },
      refresh() {
        return axios.get('/csrf-token').then(res => {
          localStorage.setItem('csrfToken', res.data.token);
        });
      }
    };
  }
};

Advanced Protection Strategies

1. Request Header Verification

In addition to tokens, specific request headers can be validated:

// Custom request header verification
app.use((req, res, next) => {
  if (req.get('X-Request-Source') !== 'web-app') {
    return res.status(403).send('Invalid request source');
  }
  next();
});

2. Behavioral Verification

Add secondary verification for critical operations:

// React confirmation dialog
function ConfirmTransfer({ amount, recipient }) {
  const [confirmed, setConfirmed] = useState(false);
  
  return (
    <div>
      {!confirmed && (
        <dialog open>
          <p>Confirm transferring {amount} to {recipient}?</p>
          <button onClick={() => setConfirmed(true)}>Confirm</button>
        </dialog>
      )}
      {confirmed && <TransferForm />}
    </div>
  );
}

3. SameSite Cookie Attribute

Modern browsers support the SameSite attribute:

// Strict mode cookie setting
Set-Cookie: sessionid=xxxx; SameSite=Strict; Secure

Practical Considerations

  1. Token Storage: Avoid storing CSRF tokens in localStorage; use HttpOnly cookies instead.
  2. Token Refresh: Refresh CSRF tokens before critical operations.
  3. Error Handling: Handle 403 status codes uniformly and guide users to re-authenticate.
  4. Logging: Record CSRF validation failures for security analysis.
// Error handling middleware
app.use((err, req, res, next) => {
  if (err.code === 'EBADCSRFTOKEN') {
    securityLogger.warn(`CSRF validation failed: ${req.ip}`);
    return res.status(403).render('error/csrf');
  }
  next(err);
});

Balancing Performance and Security

CSRF protection can impact application performance; optimize appropriately:

  1. Token Caching: Exempt static resource requests from CSRF validation.
  2. Domain Whitelisting: Configure trusted domains to reduce validation overhead.
  3. Lazy Validation: Delay validation for non-sensitive operations.
# Nginx configuration example
location ~ ^/api/secure/ {
  add_header X-Frame-Options "DENY";
  add_header X-Content-Type-Options "nosniff";
}

location ~ ^/static/ {
  expires 1y;
  add_header Cache-Control "public";
}

Testing and Validation

Comprehensive testing ensures protection effectiveness:

// Jest test cases
describe('CSRF Protection', () => {
  test('Should reject POST requests without CSRF header', async () => {
    const res = await request(app)
      .post('/transfer')
      .expect(403);
  });

  test('Should accept requests with valid CSRF header', async () => {
    const token = await getCSRFToken();
    const res = await request(app)
      .post('/transfer')
      .set('X-CSRF-TOKEN', token)
      .expect(200);
  });
});

Synergy with Other Security Measures

CSRF protection should work with other security mechanisms:

  1. CSP Policy: Restrict external resource loading.
  2. XSS Protection: Prevent token theft.
  3. Rate Limiting: Block brute-force attacks.
<!-- CSP policy example -->
<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; script-src 'self' 'unsafe-inline'">

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.