๐Ÿ›ก๏ธ แžšแžฟแž„แžšแŸ‰แžถแžœแžขแŸ†แž–แžธแž€แžถแžšแž€แžถแžšแž–แžถแžš Website Next.js แžŠแŸ„แž™ Security Headers

0 Comments

Image

แž“แŸ…แžแŸ’แž„แŸƒแž˜แžฝแž™ แžแŸ’แž‰แžปแŸ†แž‡แžถแžขแŸ’แž“แž€แžขแž—แžทแžœแžŒแŸ’แžแž“แŸ Web แž”แžถแž“แž”แž„แŸ’แž€แžพแž Website แž˜แžฝแž™แžŠแŸ„แž™แž”แŸ’แžšแžพ Next.jsแŸ” Website แžŠแŸ†แžŽแžพแžšแž€แžถแžšแž›แŸ’แžข แžšแž แŸแžŸ แž“แžทแž„แžŸแŸ’แžขแžถแž แž”แŸ‰แžปแž“แŸ’แžแŸ‚แž˜แžถแž“แžŸแŸ†แžŽแžฝแžšแž˜แžฝแž™แž€แžพแžแžกแžพแž„แž€แŸ’แž“แžปแž„แž…แžทแžแŸ’แžแžแŸ’แž‰แžปแŸ†แŸ–

โ€œแžแžพ Website แžšแž”แžŸแŸ‹แžแŸ’แž‰แžปแŸ†แž˜แžถแž“แžŸแžปแžœแžแŸ’แžแžทแž—แžถแž–แž‚แŸ’แžšแž”แŸ‹แž‚แŸ’แžšแžถแž“แŸ‹แž แžพแž™แžฌแž“แŸ…?โ€

แž“แŸ…แž›แžพแžขแŸŠแžธแž“แž’แžบแžŽแžทแž แž˜แžทแž“แž˜แŸ‚แž“แž˜แžถแž“แžแŸ‚แžขแŸ’แž“แž€แž”แŸ’แžšแžพแž”แŸ’แžšแžถแžŸแŸ‹แž›แŸ’แžขแŸ—แž‘แŸแŸ” แž˜แžถแž“แžขแŸ’แž“แž€แžœแžถแž™แž”แŸ’แžšแž แžถแžš (Attackers) แžŠแŸ‚แž›แž–แŸ’แž™แžถแž™แžถแž˜แž›แžฝแž…แž‘แžทแž“แŸ’แž“แž“แŸแž™, Inject Script, แžฌ Track แžขแŸ’แž“แž€แž”แŸ’แžšแžพแž”แŸ’แžšแžถแžŸแŸ‹แŸ” แžŠแžผแž…แŸ’แž“แŸแŸ‡ แžแŸ’แž‰แžปแŸ†แž”แžถแž“แžŸแž˜แŸ’แžšแŸแž…แž…แžทแžแŸ’แžแž”แŸ’แžšแžพ HTTP Security Headers แž€แŸ’แž“แžปแž„ Next.jsแŸ”

๐Ÿ” Security Headers แž‚แžบแž‡แžถแžขแŸ’แžœแžธ?

Security Headers แž‚แžบแž‡แžถ HTTP Headers แžŠแŸ‚แž› Browser แžขแžถแž“ แžŠแžพแž˜แŸ’แž”แžธแžŠแžนแž„แžแžถ Website แž“แŸแŸ‡แžแŸ’แžšแžผแžœแžขแž“แžปแž‰แŸ’แž‰แžถแž แžฌแž แžถแž˜แžƒแžถแžแŸ‹แžขแŸ’แžœแžธแžแŸ’แž›แŸ‡แŸ” แžœแžถแž‡แžถ แž‡แž‰แŸ’แž‡แžถแŸ†แž„แž€แžถแžšแž–แžถแžš (Security Layer) แž˜แžฝแž™แžŸแŸ†แžแžถแž“แŸ‹แžŽแžถแžŸแŸ‹ แžŸแž˜แŸ’แžšแžถแž”แŸ‹ Web Application แžŸแž˜แŸแž™แž‘แŸ†แž“แžพแž”แŸ”

โš™๏ธ แž€แžถแžšแž€แŸ†แžŽแžแŸ‹ Security Headers แž€แŸ’แž“แžปแž„ Next.js

แž€แŸ’แž“แžปแž„ Next.js แž™แžพแž„แžขแžถแž…แž€แŸ†แžŽแžแŸ‹ headers แž“แŸ…แž€แŸ’แž“แžปแž„ next.config.js แžŠแžผแž…แž“แŸแŸ‡แŸ– (แžขแŸ’แž“แž€แžขแžถแž…แžŠแžถแž€แŸ‹ code block แž“แŸแŸ‡แž“แŸ… Medium)

โœ… 1. X-DNS-Prefetch-Control

X-DNS-Prefetch-Control: on

๐Ÿ”น แžขแž“แžปแž‰แŸ’แž‰แžถแžแžฑแŸ’แž™ browser prefetch DNS แžŠแžพแž˜แŸ’แž”แžธแž”แž„แŸ’แž€แžพแž“ performance แž“แžทแž„แž€แžถแžแŸ‹แž”แž“แŸ’แžแž™ latencyแŸ”

โœ… 2. X-Content-Type-Options

X-Content-Type-Options: nosniff

๐Ÿ”น แž€แžถแžšแž–แžถแžš browser แž˜แžทแž“แžฑแŸ’แž™แž”แŸ‰แžถแž“แŸ‹แžŸแŸ’แž˜แžถแž“ content-type แžแžปแžŸแŸ— แžŠแŸ‚แž›แžขแžถแž…แž”แžŽแŸ’แžแžถแž›แžฑแŸ’แž™แž˜แžถแž“ XSS attackแŸ”

โœ… 3. Strict-Transport-Security (HSTS)

max-age=63072000; includeSubDomains; preload

๐Ÿ”น แž”แž„แŸ’แžแŸ†แžฑแŸ’แž™ website แž”แŸ’แžšแžพ HTTPS แž‡แžถแž“แžทแž…แŸ’แž… ๐Ÿ”น แž€แžถแžšแž–แžถแžš Man-in-the-Middle attack

โœ… 4. Referrer-Policy

strict-origin-when-cross-origin

๐Ÿ”น แž€แžถแžšแž–แžถแžšแž‘แžทแž“แŸ’แž“แž“แŸแž™ URL แž˜แžทแž“แžฑแŸ’แž™แž•แŸ’แž‰แžพแž–แŸแž‰แž›แŸแž‰แž‘แŸ… website แžแžถแž„แž€แŸ’แžšแŸ…แŸ”

โœ… 5. Permissions-Policy

camera=(), microphone=(), geolocation=()

๐Ÿ”น แž”แžทแž‘ access แž‘แŸ… Hardware แž“แžทแž„ API แžŠแŸ‚แž›แž˜แžทแž“แž…แžถแŸ†แž”แžถแž…แŸ‹ ๐Ÿ”น แž€แžถแžแŸ‹แž”แž“แŸ’แžแž™ privacy risk

โœ… 6. Cross-Origin-Opener-Policy

same-origin

๐Ÿ”น แž€แžถแžšแž–แžถแžš Cross-Origin attacks ๐Ÿ”น แžŸแŸ†แžแžถแž“แŸ‹แžŸแž˜แŸ’แžšแžถแž”แŸ‹ isolation แž“แžทแž„ performance

โœ… 7. X-Robots-Tag

index, follow

๐Ÿ”น แžขแž“แžปแž‰แŸ’แž‰แžถแž Search Engine index website ๐Ÿ”น แž›แŸ’แžขแžŸแž˜แŸ’แžšแžถแž”แŸ‹ SEO ๐Ÿงฑ Content Security Policy (CSP) โ€“ แž‡แž‰แŸ’แž‡แžถแŸ†แž„แžŸแžปแžœแžแŸ’แžแžทแž—แžถแž–แž’แŸ†แž”แŸ†แž•แžปแž

CSP แž‡แžถ header แžŸแŸ†แžแžถแž“แŸ‹แž”แŸ†แž•แžปแžแž€แŸ’แž“แžปแž„แž€แžถแžšแž€แžถแžšแž–แžถแžš XSS (Cross-Site Scripting)แŸ”

๐Ÿ” แžขแŸ’แžœแžธแžŠแŸ‚แž› CSP แžšแž”แžŸแŸ‹แž™แžพแž„แž’แŸ’แžœแžพแž”แžถแž“

แžขแž“แžปแž‰แŸ’แž‰แžถแž script แžแŸ‚แž–แžธ self, Umami, Facebook

แžขแž“แžปแž‰แŸ’แž‰แžถแž iframe แžแŸ‚แž–แžธ YouTube, Facebook, Google Maps

แž”แžทแž‘ object-src

แž”แžทแž‘ form submit แž‘แŸ… domain แžแžถแž„แž€แŸ’แžšแŸ…

แž”แž„แŸ’แžแŸ† upgrade HTTP โ†’ HTTPS

๐Ÿ‘‰ แž“แŸแŸ‡แž’แŸ’แžœแžพแžฑแŸ’แž™ Website แž˜แžถแž“แžŸแžปแžœแžแŸ’แžแžทแž—แžถแž–แžแŸ’แž–แžŸแŸ‹ แž”แŸ‰แžปแž“แŸ’แžแŸ‚ แž“แŸ…แžแŸ‚ compatible แž‡แžถแž˜แžฝแž™ YouTube แž“แžทแž„ Facebook Embed

๐ŸŽฏ แž˜แŸแžšแŸ€แž“แžŠแŸ‚แž›แžแŸ’แž‰แžปแŸ†แž”แžถแž“แžšแŸ€แž“

โ Website แž›แŸ’แžข แž˜แžทแž“แž˜แŸ‚แž“แžแŸ’แžšแžนแž˜แžแŸ‚แžŸแŸ’แžขแžถแž แž“แžทแž„แžšแž แŸแžŸแž‘แŸ แž”แŸ‰แžปแž“แŸ’แžแŸ‚แžแŸ’แžšแžผแžœแž˜แžถแž“ โ€œแžŸแžปแžœแžแŸ’แžแžทแž—แžถแž–โ€ แžŸแž˜แŸ’แžšแžถแž”แŸ‹แžขแŸ’แž“แž€แž”แŸ’แžšแžพแž”แŸ’แžšแžถแžŸแŸ‹ โž

Next.js แž˜แžทแž“แžแŸ’แžšแžนแž˜แžแŸ‚แž‡แžถ Framework แžŸแž˜แŸ’แžšแžถแž”แŸ‹ UI แž”แŸ‰แžปแžŽแŸ’แžŽแŸ„แŸ‡แž‘แŸ แžœแžถแž‡แžถแžงแž”แž€แžšแžŽแŸแžŠแŸแžแŸ’แž›แžถแŸ†แž„ แžŸแž˜แŸ’แžšแžถแž”แŸ‹แž€แžŸแžถแž„ Secure Production Website แž”แŸ’แžšแžŸแžทแž“แž”แžพแž™แžพแž„แž”แŸ’แžšแžพแžœแžถแžฑแŸ’แž™แžแŸ’แžšแžนแž˜แžแŸ’แžšแžผแžœแŸ”

โœ๏ธ แžŸแŸแž…แž€แŸ’แžแžธแžŸแž“แŸ’แž“แžทแžŠแŸ’แž‹แžถแž“

แž”แžพแžขแŸ’แž“แž€แž€แŸ†แž–แžปแž„แž”แŸ’แžšแžพ Next.js แžŸแž˜แŸ’แžšแžถแž”แŸ‹:

Company Website

Portfolio

SaaS

Blog (Medium-style)

๐Ÿ‘‰ แž€แžปแŸ†แž˜แžพแž›แžšแŸ†แž›แž„ Security Headers แžœแžถแž‡แžถแž‡แŸ†แž แžถแž“แžแžผแž… แž”แŸ‰แžปแž“แŸ’แžแŸ‚แž˜แžถแž“แžขแžแŸ’แžแž”แŸ’แžšแž™แŸ„แž‡แž“แŸแž’แŸ† ๐Ÿš€

แž”แž„แŸ’แž แžถแž‰ source code

import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  // แž”แžพแž€ React Strict Mode แžŠแžพแž˜แŸ’แž”แžธ catch bug แž–แŸแž› dev
  reactStrictMode: true,

  // แž”แžทแž‘ dev indicator (build status icon)
  devIndicators: false,

  // แž›แžปแž” "X-Powered-By: Next.js" แžŠแžพแž˜แŸ’แž”แžธแž€แžถแžแŸ‹แž”แž“แŸ’แžแž™ fingerprinting
  poweredByHeader: false,

  // แž€แŸ†แžŽแžแŸ‹ image domain แžŠแŸ‚แž›แžขแžถแž… load แž”แžถแž“ (YouTube thumbnail)
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'i.ytimg.com',
      },
    ],
  },

  // HTTP Security Headers
  async headers() {
    return [
      {
        // แžขแž“แžปแžœแžแŸ’แž headers แž‘แŸ…แž‚แŸ’แžšแž”แŸ‹ route
        source: '/(.*)',
        headers: [
          // แžขแž“แžปแž‰แŸ’แž‰แžถแž DNS Prefetch (performance)
          { key: 'X-DNS-Prefetch-Control', value: 'on' },

          // แž€แžถแžšแž–แžถแžš MIME sniffing (XSS protection)
          { key: 'X-Content-Type-Options', value: 'nosniff' },

          // แž”แž„แŸ’แžแŸ† HTTPS แž‡แžถแž“แžทแž…แŸ’แž… (HSTS)
          {
            key: 'Strict-Transport-Security',
            value: 'max-age=63072000; includeSubDomains; preload',
          },

          // แž€แžถแžแŸ‹แž”แž“แŸ’แžแž™ referrer data แž–แŸแž› link แž‘แŸ… site แžแžถแž„แž€แŸ’แžšแŸ…
          {
            key: 'Referrer-Policy',
            value: 'strict-origin-when-cross-origin',
          },

          // แž”แžทแž‘ access แž‘แŸ… hardware / browser features
          {
            key: 'Permissions-Policy',
            value:
              'camera=(), microphone=(), geolocation=(), payment=(), usb=(), bluetooth=()',
          },

          // แž€แžถแžšแž–แžถแžš cross-origin window attack
          { key: 'Cross-Origin-Opener-Policy', value: 'same-origin' },

          // แžขแž“แžปแž‰แŸ’แž‰แžถแž search engine index (SEO)
          { key: 'X-Robots-Tag', value: 'index, follow' },

          // ๐Ÿ›ก๏ธ Content Security Policy (CSP)
          {
            key: 'Content-Security-Policy',
            value: `
              default-src 'self';

              script-src
                'self'
                'unsafe-inline'
                https://cloud.umami.is
                https://connect.facebook.net;

              style-src
                'self'
                'unsafe-inline';

              img-src
                'self'
                data:
                https:
                https://*.fbcdn.net
                https://i.ytimg.com;

              font-src 'self';

              connect-src
                'self'
                https://api-gateway.umami.dev
                https://cloud.umami.is
                https://graph.facebook.com;

              frame-src
                https://www.facebook.com
                https://www.youtube.com
                https://www.youtube-nocookie.com
                https://www.google.com
                https://maps.google.com;

              object-src 'none';
              frame-ancestors 'self';
              base-uri 'self';
              form-action 'self';
              upgrade-insecure-requests;
            `.replace(/\s{2,}/g, ' ').trim(),
          },
        ],
      },
    ];
  },
};

export default nextConfig;