Modern Frontend Frameworklerinde Güvenlik Zafiyetleri

Gauloran

Moderasyon Tim Lideri
7 Tem 2013
8,347
874
Blackwell Academy
vRqdXHv.gif

Bu konuda modern frontend frameworklerinde güvenlik zafiyetlerini inceleyeceğiz. Bütün frameworkler için genel frontend güvenliği için bir liste yapacağız. Bu güvenlik açıklarını anlayıp aynı zamanda pratik çözümler üretip kodlu örnekler vereceğiz.

1. Cross-Site Scripting (XSS)
DOM-XSS-Zafiyeti.png


React, Vue ve Angular gibi frameworkler de 3.parti kütüphaneleri standart yapılması gereken şeylerin hatalı yapılması sonucunda xss saldırılarına karşı savunmasız olabilir. XSS'in türleri stored xss, reflected xss ve dom-based xss diye ayırabiliriz.

JavaScript:
import React, { useState } from 'react';
import DOMPurify from 'dompurify';

const UserComments = () => {
  const [comments, setComments] = useState([
    // Assume these comments are fetched from a server
    { id: 1, content: '<script>alert("XSS saldırısı!")</script>...!' },
    { id: 2, content: 'diger post.' },
    // daha fazla post
  ]);

  const createMarkup = (htmlContent) => {
    return { __html: DOMPurify.sanitize(htmlContent) };
  };

  return (
    <div>
      <h2>kullanici yorumlari</h2>
      <ul>
        {comments.map((comment) => (
          <li key={comment.id} dangerouslySetInnerHTML={createMarkup(comment.content)} />
        ))}
      </ul>
    </div>
  );
};

export default UserComments;

burada useState kullanılmış postlar muhtemelen bir veritabanından gelecek. DOMPurify.sanitize html içeriğini temizlemek için kullanılmış potansiyel riskleri azaltmak için. Yorumlarda React'ın htmlyi dom'a yerleştirmek için dangerouslySetInnerHTML özelliği kullanılıyor fakat içerik temizlendiği için XSS riski azalıyor. Zaten çoğu durumda dangerouslySetInnerHTML kullanılmamalı. DOMPurify yaygın olarak kullanılıyor html içeriğini xss saldırılarına karşı temizlemek için. Gerçek bir uygulamada data size veritabanından geldiğinde gelen içeriği tarayıcıda göstermeden önce temizlemek önemli.

vRqdXHv.gif


2- CSP
content-security-policy.jpg


Web uygulamalarını korumak için xss dahil diğer çeşitli saldırılardan korumak için çok önemlidir. CSP hangi kaynakların yüklenebileceğini ve tarayıcı tarafından çalıştırılacağını belirlemenizi sağlar.

Caddy örneği (caddy go dilinde yazılmış bir web server) nginx'e alternatif yani:


Kod:
# CSP Header
header Content-Security-Policy "script-src 'self' 'unsafe-inline' http://localhost:5173 https://static.cloudflareinsights.com https://www.clarity.ms https://accounts.google.com https://upload-widget.cloudinary.com https://maps.googleapis.com https://www.googletagmanager.com;"

Nginx örneği:

Benzer şekilde:


Kod:
codeserver {
    # ... diger konfigurasyonlar ...

    add_header Content-Security-Policy "script-src 'self' 'unsafe-inline' http://localhost:5173 https://static.cloudflareinsights.com https://www.clarity.ms https://accounts.google.com https://upload-widget.cloudinary.com https://maps.googleapis.com https://www.googletagmanager.com;"

    # ... diger konfigurasyonlar ...
}

inline scriptlerini kullanmamaya çalışın. Bu tür scriptleri sunucuda güvenilir bir alan adında barındırdığınız harici olan dosyalara taşımak daha mantıklıdır. uygulama geliştikçe csp gözden geçirilmeli test edilmeli. csp'yi sadece rapor modunda çalıştırabilirsiniz işinizi kolaylaştırır.

vRqdXHv.gif


3- CSRF
61f251b52a583fa4149b98c0_CSRF%20Preview.jpg


CSRF de kullanıcının etkileşimde olduğu e-postaya ya da siteye çeşitli kötü niyetli isteklerle yapılır. Örnek olarak kullanıcı bir banka uygulaması sitesine giriş yapıyor tarayıcı da çerezleri saklıyor. Ondan sonra bu adam kötü niyetli sitemizi ziyaret ediyor bu site de bir fon transferini tetikleyen gizli bir form içeren bir site. Adam bir şeye tıklıyor ve bu form siteye gönderiliyor banka da gelen istekte sorun göremiyor. CSRF saldırılarından korunmak için formlarda anti csrf tokenleri kullanılabilir. Bu tokenlar sunucu tarafında doğrulandığı için az önce bahsettiğim zararlı isteğin sitenin kendi formundan gelmediğini anlar.

CSRF'yi önlemek için bir örnek (Svelte):

Kod:
<script>
  import { onMount } from 'svelte';
  import axios from 'axios';

  let csrfToken = '';

  onMount(async () => {
    try {
      const response = await axios.get('/api/get-csrf-token');
      csrfToken = response.data.csrfToken;
    } catch (error) {
      console.error('Error fetching CSRF token:', error);
    }
  });

  async function submitForm() {
    const formData = new FormData();
    formData.append('_csrf', csrfToken);
    //Diger datalaar

    try {
      const response = await axios.post('/api/submit-form', formData);
      // Handle success
    } catch (error) {
      // Handle error
    }
  }
</script>

<form on:submit|preventDefault={submitForm}>
  <input type="hidden" name="_csrf" bind:value={csrfToken} />
  <!-- buraya form alani -->
  <button type="submit">Submit</button>
</form>

(Express.js) Backend:

server tarafında helmet gibi bir package kullanabiliriz CSRF tokenlarını oluşturup doğrulamak için:


Kod:
const express = require('express');
const helmet = require('helmet');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const crypto = require('crypto');

const app = express();

app.use(helmet());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());

const generateCsrfToken = () => {
  return crypto.randomBytes(100).toString('base64'); // Random token
};

// middleware
const csrfMiddleware = (req, res, next) => {
  if (!req.cookies.csrfToken) {
    const csrfToken = generateCsrfToken();
    res.cookie('csrfToken', csrfToken, { httpOnly: true });
    req.csrfToken = csrfToken;
  } else {
    req.csrfToken = req.cookies.csrfToken;
  }
  next();
};

// csrftoken
app.get('/api/get-csrf-token', csrfMiddleware, (req, res) => {
  res.json({ csrfToken: req.csrfToken });
});

//csrf token validasyonu
app.post('/api/submit-form', csrfMiddleware, (req, res) => {
  if (req.body._csrf !== req.csrfToken) {
    return res.status(403).send('token eslesmesi olmad');
  }
  // Handle your form submission
  res.json({ message: 'form basariyla gonderildi' });
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

vRqdXHv.gif


4- IDOR
prevent-IDOR-vulnerabilities.png


IDOR uygulamada kullanıcı tarafından gelen girdilere dayanarak nesnelere doğrudan erişim sağlanan bir güvenlik zafiyeti. Güvensiz doğrudan nesne referansı, dijital güvenlikteki bir tür erişim denetimi güvenlik açığıdır. Yetki kontrolü olmadan kullanıcılara veritabanı kayıtlarını açmak gibi. Bunu önlemek için bir örnek yapalım. Diyelim ki kullanıcılar kendi profil ayarlarını işte link de şu şekilde example.com/user/123. Eğer doğru düzgün erişim izinleri yapılmadıysa kullanıcı url'i example.com/user/124 olarak değiştirebilir ve başka bir üyenin profiline erişebilir. Sunucu taraflı doğrulama yapılırsa yani istenen profilin kaynaktakiyle eşleşip eşleşmediğini kontrol ederek bu zafiyetten kurtulabiliriz.


Kod:
const express = require('express');
const app = express();
const session = require('express-session');

// diyelim ki kullanici datasini getirmek icin bir fonksiyonumuz var
const getUserById = require('./getUserById');

app.use(session({
  secret: 'your-secret',
  resave: false,
  saveUninitialized: true
}));

app.get('/user/:id', (req, res) => {
  const userId = req.params.id;
  const loggedInUserId = req.session.userId;

  // kontrol
  if (userId === loggedInUserId) {
    getUserById(userId, (err, user) => {
      if (err) {
        return res.status(500).send('interval server error');
      }
      if (!user) {
        return res.status(404).send('kullanici bulunamadi');
      }
      res.json(user);
    });
  } else {
    res.status(403).send('erisim reddedildi');
  }
});

app.listen(3000, () => console.log('Server 3000 portunda'));

Express kullanıyoruz İlk olarak, gerekli şeyleri (express ve express-session) ekliyoruz. Ardından, bir middleware yapmak gerekiyor. oturumları şifrelemek ve saklamak için bir key belirlenir . /user/:id endpoint'i, belirli bir kullanıcıya sahip kullanıcı verilerini döndürmek için oluşturuluyor. Özetle istekte belirtilen kullanıcıyla oturumdaki kullanıcı eşleşmiyorsa erişim reddedilir. Böylece, kullanıcılar sadece kendi bilgilerine erişebilirler. Bu kodlar, güvenli ve yetkilendirilmiş bir API sağlamak için temel alınabilir.

vRqdXHv.gif


Screenshot_2022-01-27_at_10.03.36.png


5- Cloudflare

Cloudflare kullanın zaten. Email address obfuscation, Server-side excludes, Hotlink protection gibi özellikler sunuluyor bunları açmak da çok faydalı olur.


6- Değişkenler

1*qJ2zZ3fiP3E4QlTc4HKd5A.png


Frontend uygulamalarının bir diğer olayı API keyleri gibi önemli şeylerin korunmasıdır. Git deposuna sızdırılmayacak şekilde ayarlayın. Webpack veya Vite kullanabilirsiniz.

Kod:
npm install dotenv --save-dev

Kod:
const dotenv = require('dotenv');
const webpack = require('webpack');

// .env dosyasındaki çevre değişkenlerini yükle
dotenv.config();

module.exports = {
  // webpack yapılandırması buraya gelecek
  plugins: [
    new webpack.DefinePlugin({
      'process.env': JSON.stringify(process.env)
    })
  ]
};

Kod:
npm install dotenv --save-dev

Kod:
import { defineConfig } from 'vite';
import dotenv from 'dotenv';

// .env dosyasındaki çevre değişkenlerini yükle
dotenv.config();

export default defineConfig({
  // vite yapılandırması buraya gelecek
});

burada da Node.js ve Webpack kullanıyoruz ilk olarak, dotenv ve webpack modülleri require ile ekliyoruz. dotenv yi , .env dosyasındaki değişkenleri yüklemek için daha sonra dotenv.config() ile .env dosyasındaki değişkenleri yüklenir. .env dosyası genellikle, uygulamanın farklı yerlerinde kullanılan değişkenlerin depolandığı bir dosya olur. module.exports kullanarak dışa aktarıyoruz. .env dosyasındaki değişkenleri içerecek şekilde tanımlayıp ve JSON formatında stringe dönüştürüyoruz

Ek olarak incelemeniz için 2 ayrı makale bırakıyorum.


 

Enistein

Kıdemli Üye
16 Eyl 2012
2,233
1,264
Amsterdam
Gauloran hocam forumun en tecrübeli hackeridir. aksini idda eden haindir.

Elinize sağlık.

Kafa karışıklılığı yaratmaması için frontend tarafından kaynaklanmayan zafiyetleri düzeltmek isterim.

idor - backend yetkilendirme kontrolünden ortaya çıkar.
csp - web sunucu ayarlarından ortaya çıkar.
 

Gauloran

Moderasyon Tim Lideri
7 Tem 2013
8,347
874
Blackwell Academy
Gauloran hocam forumun en tecrübeli hackeridir. aksini idda eden haindir.

Elinize sağlık.

Kafa karışıklılığı yaratmaması için frontend tarafından kaynaklanmayan zafiyetleri düzeltmek isterim.

idor - backend yetkilendirme kontrolünden ortaya çıkar.
csp - web sunucu ayarlarından ortaya çıkar.
tesekkur ederim enis bey
 
Son düzenleme:
23 Eki 2023
195
54
vRqdXHv.gif

Bu konuda modern frontend frameworklerinde güvenlik zafiyetlerini inceleyeceğiz. Bütün frameworkler için genel frontend güvenliği için bir liste yapacağız. Bu güvenlik açıklarını anlayıp aynı zamanda pratik çözümler üretip kodlu örnekler vereceğiz.

1. Cross-Site Scripting (XSS)
DOM-XSS-Zafiyeti.png


React, Vue ve Angular gibi frameworkler de 3.parti kütüphaneleri standart yapılması gereken şeylerin hatalı yapılması sonucunda xss saldırılarına karşı savunmasız olabilir. XSS'in türleri stored xss, reflected xss ve dom-based xss diye ayırabiliriz.

JavaScript:
import React, { useState } from 'react';
import DOMPurify from 'dompurify';

const UserComments = () => {
  const [comments, setComments] = useState([
    // Assume these comments are fetched from a server
    { id: 1, content: '<script>alert("XSS saldırısı!")</script>...!' },
    { id: 2, content: 'diger post.' },
    // daha fazla post
  ]);

  const createMarkup = (htmlContent) => {
    return { __html: DOMPurify.sanitize(htmlContent) };
  };

  return (
    <div>
      <h2>kullanici yorumlari</h2>
      <ul>
        {comments.map((comment) => (
          <li key={comment.id} dangerouslySetInnerHTML={createMarkup(comment.content)} />
        ))}
      </ul>
    </div>
  );
};

export default UserComments;

burada useState kullanılmış postlar muhtemelen bir veritabanından gelecek. DOMPurify.sanitize html içeriğini temizlemek için kullanılmış potansiyel riskleri azaltmak için. Yorumlarda React'ın htmlyi dom'a yerleştirmek için dangerouslySetInnerHTML özelliği kullanılıyor fakat içerik temizlendiği için XSS riski azalıyor. Zaten çoğu durumda dangerouslySetInnerHTML kullanılmamalı. DOMPurify yaygın olarak kullanılıyor html içeriğini xss saldırılarına karşı temizlemek için. Gerçek bir uygulamada data size veritabanından geldiğinde gelen içeriği tarayıcıda göstermeden önce temizlemek önemli.

vRqdXHv.gif


2- CSP
content-security-policy.jpg


Web uygulamalarını korumak için xss dahil diğer çeşitli saldırılardan korumak için çok önemlidir. CSP hangi kaynakların yüklenebileceğini ve tarayıcı tarafından çalıştırılacağını belirlemenizi sağlar.

Caddy örneği (caddy go dilinde yazılmış bir web server) nginx'e alternatif yani:


Kod:
# CSP Header
header Content-Security-Policy "script-src 'self' 'unsafe-inline' http://localhost:5173 https://static.cloudflareinsights.com https://www.clarity.ms https://accounts.google.com https://upload-widget.cloudinary.com https://maps.googleapis.com https://www.googletagmanager.com;"

Nginx örneği:

Benzer şekilde:


Kod:
codeserver {
    # ... diger konfigurasyonlar ...

    add_header Content-Security-Policy "script-src 'self' 'unsafe-inline' http://localhost:5173 https://static.cloudflareinsights.com https://www.clarity.ms https://accounts.google.com https://upload-widget.cloudinary.com https://maps.googleapis.com https://www.googletagmanager.com;"

    # ... diger konfigurasyonlar ...
}

inline scriptlerini kullanmamaya çalışın. Bu tür scriptleri sunucuda güvenilir bir alan adında barındırdığınız harici olan dosyalara taşımak daha mantıklıdır. uygulama geliştikçe csp gözden geçirilmeli test edilmeli. csp'yi sadece rapor modunda çalıştırabilirsiniz işinizi kolaylaştırır.

vRqdXHv.gif


3- CSRF
61f251b52a583fa4149b98c0_CSRF%20Preview.jpg


CSRF de kullanıcının etkileşimde olduğu e-postaya ya da siteye çeşitli kötü niyetli isteklerle yapılır. Örnek olarak kullanıcı bir banka uygulaması sitesine giriş yapıyor tarayıcı da çerezleri saklıyor. Ondan sonra bu adam kötü niyetli sitemizi ziyaret ediyor bu site de bir fon transferini tetikleyen gizli bir form içeren bir site. Adam bir şeye tıklıyor ve bu form siteye gönderiliyor banka da gelen istekte sorun göremiyor. CSRF saldırılarından korunmak için formlarda anti csrf tokenleri kullanılabilir. Bu tokenlar sunucu tarafında doğrulandığı için az önce bahsettiğim zararlı isteğin sitenin kendi formundan gelmediğini anlar.

CSRF'yi önlemek için bir örnek (Svelte):

Kod:
<script>
  import { onMount } from 'svelte';
  import axios from 'axios';

  let csrfToken = '';

  onMount(async () => {
    try {
      const response = await axios.get('/api/get-csrf-token');
      csrfToken = response.data.csrfToken;
    } catch (error) {
      console.error('Error fetching CSRF token:', error);
    }
  });

  async function submitForm() {
    const formData = new FormData();
    formData.append('_csrf', csrfToken);
    //Diger datalaar

    try {
      const response = await axios.post('/api/submit-form', formData);
      // Handle success
    } catch (error) {
      // Handle error
    }
  }
</script>

<form on:submit|preventDefault={submitForm}>
  <input type="hidden" name="_csrf" bind:value={csrfToken} />
  <!-- buraya form alani -->
  <button type="submit">Submit</button>
</form>

(Express.js) Backend:

server tarafında helmet gibi bir package kullanabiliriz CSRF tokenlarını oluşturup doğrulamak için:


Kod:
const express = require('express');
const helmet = require('helmet');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const crypto = require('crypto');

const app = express();

app.use(helmet());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());

const generateCsrfToken = () => {
  return crypto.randomBytes(100).toString('base64'); // Random token
};

// middleware
const csrfMiddleware = (req, res, next) => {
  if (!req.cookies.csrfToken) {
    const csrfToken = generateCsrfToken();
    res.cookie('csrfToken', csrfToken, { httpOnly: true });
    req.csrfToken = csrfToken;
  } else {
    req.csrfToken = req.cookies.csrfToken;
  }
  next();
};

// csrftoken
app.get('/api/get-csrf-token', csrfMiddleware, (req, res) => {
  res.json({ csrfToken: req.csrfToken });
});

//csrf token validasyonu
app.post('/api/submit-form', csrfMiddleware, (req, res) => {
  if (req.body._csrf !== req.csrfToken) {
    return res.status(403).send('token eslesmesi olmad');
  }
  // Handle your form submission
  res.json({ message: 'form basariyla gonderildi' });
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

vRqdXHv.gif


4- IDOR
prevent-IDOR-vulnerabilities.png


IDOR uygulamada kullanıcı tarafından gelen girdilere dayanarak nesnelere doğrudan erişim sağlanan bir güvenlik zafiyeti. Güvensiz doğrudan nesne referansı, dijital güvenlikteki bir tür erişim denetimi güvenlik açığıdır. Yetki kontrolü olmadan kullanıcılara veritabanı kayıtlarını açmak gibi. Bunu önlemek için bir örnek yapalım. Diyelim ki kullanıcılar kendi profil ayarlarını işte link de şu şekilde example.com/user/123. Eğer doğru düzgün erişim izinleri yapılmadıysa kullanıcı url'i example.com/user/124 olarak değiştirebilir ve başka bir üyenin profiline erişebilir. Sunucu taraflı doğrulama yapılırsa yani istenen profilin kaynaktakiyle eşleşip eşleşmediğini kontrol ederek bu zafiyetten kurtulabiliriz.


Kod:
const express = require('express');
const app = express();
const session = require('express-session');

// diyelim ki kullanici datasini getirmek icin bir fonksiyonumuz var
const getUserById = require('./getUserById');

app.use(session({
  secret: 'your-secret',
  resave: false,
  saveUninitialized: true
}));

app.get('/user/:id', (req, res) => {
  const userId = req.params.id;
  const loggedInUserId = req.session.userId;

  // kontrol
  if (userId === loggedInUserId) {
    getUserById(userId, (err, user) => {
      if (err) {
        return res.status(500).send('interval server error');
      }
      if (!user) {
        return res.status(404).send('kullanici bulunamadi');
      }
      res.json(user);
    });
  } else {
    res.status(403).send('erisim reddedildi');
  }
});

app.listen(3000, () => console.log('Server 3000 portunda'));

Express kullanıyoruz İlk olarak, gerekli şeyleri (express ve express-session) ekliyoruz. Ardından, bir middleware yapmak gerekiyor. oturumları şifrelemek ve saklamak için bir key belirlenir . /user/:id endpoint'i, belirli bir kullanıcıya sahip kullanıcı verilerini döndürmek için oluşturuluyor. Özetle istekte belirtilen kullanıcıyla oturumdaki kullanıcı eşleşmiyorsa erişim reddedilir. Böylece, kullanıcılar sadece kendi bilgilerine erişebilirler. Bu kodlar, güvenli ve yetkilendirilmiş bir API sağlamak için temel alınabilir.

vRqdXHv.gif


Screenshot_2022-01-27_at_10.03.36.png


5- Cloudflare

Cloudflare kullanın zaten. Email address obfuscation, Server-side excludes, Hotlink protection gibi özellikler sunuluyor bunları açmak da çok faydalı olur.


6- Değişkenler

1*qJ2zZ3fiP3E4QlTc4HKd5A.png


Frontend uygulamalarının bir diğer olayı API keyleri gibi önemli şeylerin korunmasıdır. Git deposuna sızdırılmayacak şekilde ayarlayın. Webpack veya Vite kullanabilirsiniz.

Kod:
npm install dotenv --save-dev

Kod:
const dotenv = require('dotenv');
const webpack = require('webpack');

// .env dosyasındaki çevre değişkenlerini yükle
dotenv.config();

module.exports = {
  // webpack yapılandırması buraya gelecek
  plugins: [
    new webpack.DefinePlugin({
      'process.env': JSON.stringify(process.env)
    })
  ]
};

Kod:
npm install dotenv --save-dev

Kod:
import { defineConfig } from 'vite';
import dotenv from 'dotenv';

// .env dosyasındaki çevre değişkenlerini yükle
dotenv.config();

export default defineConfig({
  // vite yapılandırması buraya gelecek
});

burada da Node.js ve Webpack kullanıyoruz ilk olarak, dotenv ve webpack modülleri require ile ekliyoruz. dotenv yi , .env dosyasındaki değişkenleri yüklemek için daha sonra dotenv.config() ile .env dosyasındaki değişkenleri yüklenir. .env dosyası genellikle, uygulamanın farklı yerlerinde kullanılan değişkenlerin depolandığı bir dosya olur. module.exports kullanarak dışa aktarıyoruz. .env dosyasındaki değişkenleri içerecek şekilde tanımlayıp ve JSON formatında stringe dönüştürüyoruz

Ek olarak incelemeniz için 2 ayrı makale bırakıyorum.


Cok detayli konu olmus hocam elinize saglik
 
Üst

Turkhackteam.org internet sitesi 5651 sayılı kanun’un 2. maddesinin 1. fıkrasının m) bendi ile aynı kanunun 5. maddesi kapsamında "Yer Sağlayıcı" konumundadır. İçerikler ön onay olmaksızın tamamen kullanıcılar tarafından oluşturulmaktadır. Turkhackteam.org; Yer sağlayıcı olarak, kullanıcılar tarafından oluşturulan içeriği ya da hukuka aykırı paylaşımı kontrol etmekle ya da araştırmakla yükümlü değildir. Türkhackteam saldırı timleri Türk sitelerine hiçbir zararlı faaliyette bulunmaz. Türkhackteam üyelerinin yaptığı bireysel hack faaliyetlerinden Türkhackteam sorumlu değildir. Sitelerinize Türkhackteam ismi kullanılarak hack faaliyetinde bulunulursa, site-sunucu erişim loglarından bu faaliyeti gerçekleştiren ip adresini tespit edip diğer kanıtlarla birlikte savcılığa suç duyurusunda bulununuz.