From 8e6d9cc64543f24ed0ea683d20574205eabb0527 Mon Sep 17 00:00:00 2001 From: Wise Date: Tue, 16 Apr 2024 22:17:43 +0200 Subject: [PATCH] New Blog Post --- .github/workflows/delete_workflows.yml | 88 +-- .github/workflows/publishGithubPages.yml | 76 +- content/post/adguard-reklam-engelleme.md | 536 ++++++------- content/post/crowdsec-anlatim.md | 640 +++++++-------- content/post/ecc-ssl-sertifikasi.de.md | 440 +++++------ content/post/ecc-ssl-sertifikasi.en.md | 440 +++++------ content/post/ecc-ssl-sertifikasi.md | 440 +++++------ content/post/fotograf-compress-magick.md | 733 ++++++++++++++++++ content/post/grigori-rasputin.md | 40 +- content/post/maximum-kart-reklami.md | 54 +- content/post/modern-kriptografi-star-wars.md | 56 +- content/post/openvpn-full-anlatim.de.md | 278 +++---- content/post/openvpn-full-anlatim.en.md | 280 +++---- content/post/openvpn-full-anlatim.md | 280 +++---- content/post/pgp-ve-gizlilik.md | 52 +- content/post/ssl-konfigurasyonu.de.md | 276 +++---- content/post/ssl-konfigurasyonu.en.md | 276 +++---- content/post/ssl-konfigurasyonu.md | 274 +++---- layouts/shortcodes/img.html.BACKUP | 50 +- .../fotograf-compress-magick/giris1.avif | Bin 0 -> 3481 bytes .../fotograf-compress-magick/giris1.png | Bin 0 -> 21179 bytes .../fotograf-compress-magick/giris1.webp | Bin 0 -> 8754 bytes .../fotograf-compress-magick/giris2.avif | Bin 0 -> 7407 bytes .../fotograf-compress-magick/giris2.png | Bin 0 -> 26766 bytes .../fotograf-compress-magick/giris2.webp | Bin 0 -> 19342 bytes .../images/fotograf-compress-magick/mid1.avif | Bin 0 -> 49311 bytes .../images/fotograf-compress-magick/mid1.png | Bin 0 -> 111943 bytes .../images/fotograf-compress-magick/mid1.webp | Bin 0 -> 67020 bytes .../images/fotograf-compress-magick/mid2.avif | Bin 0 -> 5603 bytes .../images/fotograf-compress-magick/mid2.png | Bin 0 -> 30265 bytes .../images/fotograf-compress-magick/mid2.webp | Bin 0 -> 17928 bytes themes/hugo-PaperMod | 2 +- 32 files changed, 3022 insertions(+), 2289 deletions(-) create mode 100644 content/post/fotograf-compress-magick.md create mode 100644 static/images/fotograf-compress-magick/giris1.avif create mode 100644 static/images/fotograf-compress-magick/giris1.png create mode 100644 static/images/fotograf-compress-magick/giris1.webp create mode 100644 static/images/fotograf-compress-magick/giris2.avif create mode 100644 static/images/fotograf-compress-magick/giris2.png create mode 100644 static/images/fotograf-compress-magick/giris2.webp create mode 100644 static/images/fotograf-compress-magick/mid1.avif create mode 100644 static/images/fotograf-compress-magick/mid1.png create mode 100644 static/images/fotograf-compress-magick/mid1.webp create mode 100644 static/images/fotograf-compress-magick/mid2.avif create mode 100644 static/images/fotograf-compress-magick/mid2.png create mode 100644 static/images/fotograf-compress-magick/mid2.webp diff --git a/.github/workflows/delete_workflows.yml b/.github/workflows/delete_workflows.yml index 47f4b98b..555f1e3b 100644 --- a/.github/workflows/delete_workflows.yml +++ b/.github/workflows/delete_workflows.yml @@ -1,44 +1,44 @@ -name: Delete old workflow runs -on: - workflow_dispatch: - inputs: - days: - description: 'Number of days.' - required: true - default: 7 - minimum_runs: - description: 'The minimum runs to keep for each workflow.' - required: true - default: 3 - delete_workflow_pattern: - description: 'The name or filename of the workflow. if not set then it will target all workflows.' - required: false - delete_workflow_by_state_pattern: - description: 'Remove workflow by state: active, deleted, disabled_fork, disabled_inactivity, disabled_manually' - required: true - default: "All" - type: choice - options: - - "All" - - active - - deleted - - disabled_inactivity - - disabled_manually - dry_run: - description: 'Only log actions, do not perform any delete operations.' - required: false - -jobs: - del_runs: - runs-on: ubuntu-latest - steps: - - name: Delete workflow runs - uses: Mattraks/delete-workflow-runs@v2 - with: - token: ${{ github.token }} - repository: ${{ github.repository }} - retain_days: ${{ github.event.inputs.days }} - keep_minimum_runs: ${{ github.event.inputs.minimum_runs }} - delete_workflow_pattern: ${{ github.event.inputs.delete_workflow_pattern }} - delete_workflow_by_state_pattern: ${{ github.event.inputs.delete_workflow_by_state_pattern }} - dry_run: ${{ github.event.inputs.dry_run }} +name: Delete old workflow runs +on: + workflow_dispatch: + inputs: + days: + description: 'Number of days.' + required: true + default: 7 + minimum_runs: + description: 'The minimum runs to keep for each workflow.' + required: true + default: 3 + delete_workflow_pattern: + description: 'The name or filename of the workflow. if not set then it will target all workflows.' + required: false + delete_workflow_by_state_pattern: + description: 'Remove workflow by state: active, deleted, disabled_fork, disabled_inactivity, disabled_manually' + required: true + default: "All" + type: choice + options: + - "All" + - active + - deleted + - disabled_inactivity + - disabled_manually + dry_run: + description: 'Only log actions, do not perform any delete operations.' + required: false + +jobs: + del_runs: + runs-on: ubuntu-latest + steps: + - name: Delete workflow runs + uses: Mattraks/delete-workflow-runs@v2 + with: + token: ${{ github.token }} + repository: ${{ github.repository }} + retain_days: ${{ github.event.inputs.days }} + keep_minimum_runs: ${{ github.event.inputs.minimum_runs }} + delete_workflow_pattern: ${{ github.event.inputs.delete_workflow_pattern }} + delete_workflow_by_state_pattern: ${{ github.event.inputs.delete_workflow_by_state_pattern }} + dry_run: ${{ github.event.inputs.dry_run }} diff --git a/.github/workflows/publishGithubPages.yml b/.github/workflows/publishGithubPages.yml index a53d1b0a..9a76e73a 100644 --- a/.github/workflows/publishGithubPages.yml +++ b/.github/workflows/publishGithubPages.yml @@ -1,38 +1,38 @@ -# This is a basic workflow to help you get started with Actions - -name: Publish to Github pages - -# Controls when the workflow will run -on: - # Triggers the workflow on push events but only for the master branch - push: - branches: [ master ] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - buildAndDeploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - fetch-depth: 0 - - - name: Install and Setup Hugo - uses: peaceiris/actions-hugo@v3 - with: - hugo-version: 'latest' - extended: true - - - name: Build site - run: hugo --minify --enableGitInfo --gc --baseURL https://wiseweb-works.github.io/blog/ - - - name: Deploy to Github Pages - uses: peaceiris/actions-gh-pages@v4 - if: github.ref == 'refs/heads/master' - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./public +# This is a basic workflow to help you get started with Actions + +name: Publish to Github pages + +# Controls when the workflow will run +on: + # Triggers the workflow on push events but only for the master branch + push: + branches: [ master ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + buildAndDeploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: true + fetch-depth: 0 + + - name: Install and Setup Hugo + uses: peaceiris/actions-hugo@v3 + with: + hugo-version: 'latest' + extended: true + + - name: Build site + run: hugo --minify --enableGitInfo --gc --baseURL https://wiseweb-works.github.io/blog/ + + - name: Deploy to Github Pages + uses: peaceiris/actions-gh-pages@v4 + if: github.ref == 'refs/heads/master' + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./public diff --git a/content/post/adguard-reklam-engelleme.md b/content/post/adguard-reklam-engelleme.md index 953b764b..b2e3d320 100644 --- a/content/post/adguard-reklam-engelleme.md +++ b/content/post/adguard-reklam-engelleme.md @@ -1,268 +1,268 @@ ---- -title: "AdGuard ile Reklam Engelleme" -date: 2023-04-06 -tags: ["windows", "ad", "adblock", "adguard", "youtubeads", "youtube", "dns", "doh", "dns-over-https", "dns-over-tls", "dns-over-Quic", "DNSSEC", "DNS-crypt","ESNI", "Encryted SNI", "ECH", "Encrypted Client Hello"] -author: "Wise" -draft: false ---- -# 1. AdGuard: Reklamsız Gezinti İçin Nihai Çözümünüz - -İnternette gezinirken sürekli karşınıza çıkan reklam ve açılır pencerelerinden sıkıldıysanız, [AdGuard Windows uygulamasını](https://adguard.com/tr/adguard-windows/overview.html) kullanmayı düşünebilirsiniz. AdGuard, yalnızca reklamları kaldırmakla kalmayıp aynı zamanda bilgisayarınızı kötü amaçlı yazılımlardan ve kimlik avı saldırılarından koruyan güçlü bir reklam engelleyicidir. Tanıdığınız ve bildiğiniz tüm reklamlara son kez sarılın artık onları bir daha göremeyeceksiniz. Çünkü bu blog gönderisinde, AdGuard'ın özelliklerini ve göz atma deneyiminizi nasıl geliştirebileceğini keşfedeceğiz. - -## 1.1 AdGuard Uygulamasının Özellikleri - -### 1.1.1 Reklam engelleyici - -* AdGuard'ın birincil özelliği, banner reklamlar, açılır pencereler ve video reklamlar dahil olmak üzere her türlü reklamı[^1] web sayfalarından kaldırabilen reklam engelleyicisidir. Bu özellik yalnızca gezinmeyi hızlandırmakla kalmaz, aynı zamanda verilerden tasarruf etmenizi sağlar ve göz yorgunluğunu azaltır. - -[^1]: `Contextual Advertising`, `Analytics Tools`, `Banner Advertising`, `Error Monitoring`, `Cookie Consent Notification`, `Youtube Ads` ve `Message Box` - -### 1.1.2 Gizlilik koruması - -* AdGuard, web sitelerinin verilerinizi toplamak için kullandığı izleme çerezlerini ve diğer izleme mekanizmalarını engelleyerek gizliliğinizi korur. Ayrıca, IP adresinizi ve diğer hassas bilgileri web sitelerinden gizleyen Gizli mod adı verilen bir özelliği de vardır. - -### 1.1.3 Ebeveyn Kontrolü - -* AdGuard, yetişkinlere uygun içerik veya diğer uygunsuz materyaller barındıran web sitelerine erişimi engellemenizi sağlayan bir ebeveyn denetimi özelliğine sahiptir. Belirli web sitelerini veya kategorileri engellemek için özel kurallar da oluşturabilirsiniz. - -### 1.1.4 Malware koruması - -* AdGuard, kötü amaçlı kod veya bağlantılar içeren web sitelerini engelleyen yerleşik bir kötü amaçlı yazılımdan koruma özelliğine sahiptir. Ayrıca tehlikeli olduğu bildirilen bir web sitesini ziyaret ettiğinizde sizi uyarabilir. - -### 1.1.5 Özelleştirilebilir Filtreler - -* AdGuard, belirli içerik türlerini veya web sitelerini engellemek için kendi filtrelerinizi oluşturmanıza veya diğer kullanıcılardan filtreler eklemenize olanak tanır. Bu özellik, gördükleriniz ve görmedikleriniz üzerinde tam kontrol sahibi olmanızı sağlar. - -### 1.1.6 Kullanıcı dostu arayüz - -* AdGuard, en acemi kullanıcılar için bile kullanımı kolaylaştıran basit ve sezgisel bir arayüze sahiptir. Tüm özelliklere ve ayarlara ana panodan kolayca erişebilirsiniz. - -### > 1.1.7 Kısa Özet - -> (TL;DR)[^2] AdGuard karşınıza çıkan reklamları engellerken aynı zamanda da kullanıcı dostu arayüzü ve özelleştirilebilir filtreleri sayesinde gizliliğinizi de korur. Ebeveyn kontrolü ve Malware koruması sayesinde ise istenmeyen sonuçlara karşı hazırlıklı olursunuz. - -[^2]: TL;DR: `Too long; Didn't read` veya `Çok uzundu; okumadım` özet geç anlamında - -## 1.2 Neden AdGuard'ı Seçmelisiniz? - -AdGuard, gelişmiş özellikleri ve kullanımı kolay arayüzü nedeniyle Windows için mevcut olan en iyi reklam engelleyicilerden biridir. İşte AdGuard'ı seçmeniz için bazı nedenler: - -### 1.2.1 Kapsamlı Reklam Engelleme - -* AdGuard, pop-up'lar, video reklamlar ve banner reklamlar dahil her türlü reklamı[^1] engelleyerek tarama deneyiminizi daha akıcı ve hızlı hale getirebilir. - -### 1.2.2 Gelişmiş Gizlilik Koruması - -* AdGuard yalnızca reklamları engellemekle kalmaz, izleme çerezlerini engelleyerek ve IP adresinizi gizleyerek gizliliğinizi de korur. - -### 1.2.3 Malware koruması - -* AdGuard'ın kötü amaçlı yazılımdan koruma özelliği, sizi kötü amaçlı web sitelerinden korur ve tehlikeli bir siteyi ziyaret ettiğinizde sizi uyarır. - -### 1.2.4 Özelleştirilebilir Filtreler - -* AdGuard'ın özelleştirilebilir filtreleri, size hangi içeriği görüp neyi görmediğiniz konusunda tam kontrol sağlar. - -### 1.2.5 Kullanımı Kolay Arayüz - -* AdGuard'ın kullanıcı dostu arayüzü, teknik uzmanlıkları ne olursa olsun tüm kullanıcılar için kullanımı kolaylaştırır. - -### > 1.2.6 Kısa Özet - -> (TL;DR) [^2] AdGuard diğer reklam engelleme yazılımları ve çözümlerinden daha gelişmiş ve hızlı bir çözüme sahiptir. Ayrıca diğer yazılımlarda olmayan Malware koruması ve Gelişmiş Gizlilik özelliklerine de sahiptir. - ----- - -# 2. AdGuard Windows Uygulaması Nasıl Kurulur - -AdGuard, bilgisayarınızı kötü amaçlı yazılımlardan ve kimlik avı saldırılarından koruyabilen ve aynı zamanda web sayfalarından her türlü reklamı[^1] kaldırabilen güçlü bir reklam engelleyicidir. Reklamsız bir tarama deneyimi yaşamak istiyorsanız, AdGuard'ı Windows PC'nize yüklemek kolay ve kolaydır. Bu blog gönderisinde, AdGuard'ı Windows PC'nize yükleme adımlarında size rehberlik edeceğiz. - -## 2.1 Adım Adım Kılavuz - -### 2.1.1 AdGuard Yükleyiciyi İndirin - -AdGuard'ı Windows PC'nize kurmanın ilk adımı, AdGuard yükleyicisini resmi web sitesinden indirmektir. AdGuard web sitesindeki "İndir" düğmesine tıklayarak yükleyiciyi indirebilirsiniz. - -![https://adguard.com/tr/adguard-windows/overview.html (Erişim Tarihi 07.04.2023)](/images/adguard/1.jpg) - -### 2.1.2 Yükleyiciyi Çalıştırın - -AdGuard yükleyicisini indirdikten sonra, PC'nizde dosyayı bulun ve yükleyiciyi çalıştırmak için üzerine çift tıklayın. Kullanıcı Hesabı Denetimi (UAC) tarafından istenirse, yükleyiciye PC'nizde değişiklik yapması için izin vermeniz gerekebilir. - -![Adguard Windows uygulaması yükleyici görüntüleri](/images/adguard/2.png) - -### 2.1.3 Kurulum Seçeneklerini Seçin - -Bir sonraki adım, AdGuard için kurulum seçeneklerini seçmektir. AdGuard'ı tüm kullanıcılar için veya yalnızca mevcut kullanıcı için yüklemeyi seçebilirsiniz. Ayrıca kurulum klasörünü seçebilir ve bir masaüstü kısayolu oluşturabilirsiniz. - -![Adguard Windows uygulaması kurulum seçenekleri](/images/adguard/3.png) - -### 2.1.4 AdGuard'ı yükleyin - -Kurulum seçeneklerini seçtikten sonra, kurulum sürecini başlatmak için "Yükle" düğmesine tıklayın. Yükleme işlemi bilgisayarınızın hızına bağlı olarak birkaç dakika sürebilir. - -![Adguard Windows uygulaması kurulum görüntüleri](/images/adguard/4.png) - -### 2.1.5 AdGuard'ı başlatın - -Yükleme tamamlandıktan sonra, AdGuard'ı masaüstü kısayolundan veya Başlat menüsünden başlatabilirsiniz. AdGuard'ı ilk kez başlattığınızda, ayarları tercihlerinize göre yapılandırmanızı isteyecektir. - -![Adguard Windows uygulaması genel ayarları](/images/adguard/5.jpg) - -### 2.1.6 Reklamsız Taramanın Keyfini Çıkarın - -AdGuard'ın ayarlarını yapılandırdıktan sonra, reklamsız bir göz atma deneyiminin keyfini çıkarabilirsiniz. AdGuard, web sayfalarından her türlü reklamı[^1] otomatik olarak kaldırarak gezinmenizi daha hızlı ve sorunsuz hale getirir. - -![https://www.youtube.com/watch?v=YW9Ojcm1Gkg (Erişim Tarihi 07.04.2023)](/images/adguard/6.jpg) - -### > 2.1.7 Kısa Özet - -> Sistem admini iseniz veya herhangi bir ayar ile uğraşmaadan direk kurmak istiyorsanız `Msiexec /q /i AdGuard.msi` komutunu kullanabilirsiniz. -> -> Alternatif olarak da halk arasında "Next > Next > Next" tabir edilen yöntemi kullanabilirsiniz. Yani `kapattım gözlerimi karanlığa, açtım ellerimi sonsuzluğa, rabbim sonum hayrola :D` diyerek her gelen sayfada hiçbir şeyi okumadan İleri/Next butonuna tıklayarak çok hızlı bir şekilde kurabilirsiniz. ----- - -# 3. AdGuard Nasıl Çalışıyor? - -AdGuard, dünya çapında milyonlarca kullanıcının güvendiği güçlü bir reklam engelleyicidir. Reklamları engelleme yollarından biri, DNS tabanlı engelleme teknikleri kullanmaktır. Bu blog gönderisinde, AdGuard'ın DNS, DNS-over-HTTPS (DoH) ve diğer teknikleri kullanarak reklamları nasıl engellediğini keşfedeceğiz. - -## 3.1 DNS Tabanlı Engelleme - -DNS tabanlı engelleme, AdGuard tarafından reklamları DNS isteklerini kara listeye alınmış bir IP adresine yönlendirerek engellemek için kullanılan bir tekniktir. Bir web sitesini ziyaret ettiğinizde, tarayıcınız, web sitesinin alan adını bir IP adresine çevirmek için bir DNS sunucusuna bir DNS isteği gönderir. AdGuard bu isteği yakalar ve kara listesine göre kontrol eder. Alan kara listedeyse AdGuard, isteği kara listedeki bir IP adresine yönlendirerek reklamın ekranınızda görüntülenmesini etkili bir şekilde engeller. - -DNS filtresi, reklamları daha bilgisayarınıza yüklenmelerine fırsat vermeden engelleyerek zamandan ve bant genişliğinden tasarruf etmenizi sağladığı için oldukça etkilidir. AdGuard'ın DNS filtresi de son derece özelleştirilebilir olup, kullanıcıların gerektiğinde belirli alanları beyaz listeye veya kara listeye almasına olanak tanır. DNS tabanlı engelleme, reklamları engellemenin basit ve etkili bir yoludur, ancak bazı sınırlamaları vardır. Örneğin, bazı reklamlar, standart olmayan bağlantı noktaları veya şifreli bağlantılar kullanarak DNS engellemesini atlayabilir. - -## 3.2 HTTPS filtresi - -HTTPS filtresi, AdGuard'ın bir başka önemli özelliğidir ve HTTPS şifrelemesi kullanan web sitelerindeki istenmeyen içeriği filtreleyerek çalışır. Birçok reklam engelleme aracı, şifreleme web sitesinin içeriğini görmelerini engellediği için HTTPS web sitelerindeki reklamları engellemekte zorlanır. Ancak, AdGuard'ın HTTPS filtresi, web sitesinin içeriğinin şifresini çözebilir ve istenmeyen reklamları veya diğer içeriği filtreleyebilir. - -HTTPS filtresi, daha fazla web sitesi gelişmiş güvenlik için HTTPS'ye geçtikçe giderek yaygınlaşan HTTPS şifrelemesi kullanan web sitelerindeki reklamları engellemede oldukça etkilidir. AdGuard'ın HTTPS filtresi de son derece özelleştirilebilir ve kullanıcıların belirli web sitelerini veya etki alanlarını beyaz veya kara listeye almasına olanak tanır. - -## 3.3 İçerik filtresi - -İçerik filtresi, AdGuard'ın bir diğer önemli özelliğidir ve web sitelerindeki istenmeyen içeriği filtreleyerek çalışır. Buna, kullanıcıların dikkatini dağıtabilecek veya rahatsız edebilecek reklamlar, açılır pencereler, Cookie (Çerez) uyarı bildirimleri, afişler ve diğer istenmeyen içerik türleri dahildir. - -İçerik filtresi, tüm etki alanlarını veya IP adreslerini engellemek yerine bir web sitesindeki belirli öğeleri hedef aldığı için oldukça etkilidir. Bu, kullanıcıların istenmeyen içerikle bombardımana tutulmadan daha akıcı bir tarama deneyiminin keyfini çıkarmasına olanak tanır. AdGuard'ın İçerik filtresi de son derece özelleştirilebilir ve kullanıcıların belirli web sitelerini veya etki alanlarını beyaz veya kara listeye almasına olanak tanır. - -## > 3.4 Kısa Özet - -> (TL;DR) [^2] ![https://adguard.com/tr/adguard-windows/overview.html (Erişim Tarihi: 07.04.2023)](/images/adguard/adguard-nasil-calisir.jpg) - ----- - -# 4. DNS ile ilgili Gelişmiş Ayalar - -DNS (Alan Adı Sistemi), insanlar tarafından okunabilen alan adlarını bilgisayarların anlayabileceği IP adreslerine çevirmek için kullanılan bir protokoldür. Ancak, DNS sorguları normal olarak 53 numaralı port üzerinden gönderilir ve herhangi bir şifreleme yapılmaz. Dolayısıyla varsayılan olarak güvenli değildir ve DNS sorguları saldırganlar tarafından ele geçirilebilir veya manipüle edilebilir. - -![https://blog.chromium.org/2020/05/a-safer-and-more-private-browsing-DoH.html (Erişim Tarihi: 07.04.2023)](/images/adguard/Unsecured-DNS.png) - -Bu sorunu çözmek için HTTPS üzerinden DNS (DoH), TLS üzerinden DNS (DoT), QUIC üzerinden DNS (DoQ) ve DNSCrypt dahil olmak üzere birkaç yeni protokol geliştirilmiştir. Blog gönderisinin bu kısmında, bu protokoller arasındaki farkları ve DNS sorgularınızı korumaya nasıl yardımcı olabileceklerini tartışacağız. DNS-over-HTTPS (DoH), DNS-over-TLS (DoT), DNS-over-QUIC (DoQ) ve DNSCrypt birçok avantaj sağlarken, dikkate alınması gereken bazı potansiyel dezavantajlar da vardır. [^3] - -[^3]: Büyük güç büyük sorumluluk getirir. -Örümcek Adam - -## 4.1 HTTPS üzerinden DNS (DoH) - -DNS-over-HTTPS (DoH), HTTPS protokolünü kullanarak DNS sorgularını şifreleyen bir protokoldür. DoH, üçüncü tarafların DNS sorgularına müdahale etmesini ve kurcalamasını önleyerek gizliliği ve güvenliği artırmak için tasarlanmıştır. DoH ile, DNS sorguları şifrelenmiş bir kanal üzerinden gönderilerek saldırganların bunları yakalamasını ve manipüle etmesini zorlaştırır. - -DoH, Firefox, Chrome ve Edge dahil olmak üzere birçok büyük web tarayıcısı tarafından desteklenir. Bir DoH uygulaması yükleyerek veya cihazınızı bir DoH sunucusu kullanacak şekilde yapılandırarak mobil cihazlarda da kullanılabilir. - -![https://blog.chromium.org/2020/05/a-safer-and-more-private-browsing-DoH.html (Erişim Tarihi: 07.04.2023)](/images/adguard/DNS-over-HTTPS.png) - -* ### 4.1.1 Dezavantajları - - * DoH'nin bir dezavantajı, belirli ortamlarda uygulanmasının zor olabilmesidir. Örneğin DoH, bazı güvenlik duvarları veya internet servis sağlayıcıları tarafından engellenebilir ve bu da kullanımını zorlaştırabilir. Ek olarak, bazı ağ yöneticileri, ağ trafiğini izlemeyi ve denetlemeyi zorlaştırabileceğinden, şifrelenmiş DNS sorgularına izin vermek istemeyebilir. - - * DoH ile ilgili bir başka olası sorun, gecikmeyi artırabilmesi ve DNS sorgularını yavaşlatabilmesidir. Bunun nedeni, DoH sorgularının, geleneksel bir DNS sorgusundan daha fazla ek yük gerektiren bir HTTPS bağlantısı üzerinden gönderilmesidir. Bu, çoğu kullanıcı için fark edilmese de, çevrimiçi oyunlar veya gerçek zamanlı video konferans gibi düşük gecikmeli DNS sorguları gerektiren uygulamalar için bir sorun olabilir. - -## 4.2 TLS üzerinden DNS (DoT) - -DNS-over-TLS (DoT), DNS sorgularını şifreleyen başka bir protokoldür, ancak HTTPS yerine Aktarım Katmanı Güvenliği (TLS) protokolünü kullanır. DoT, DoH ile benzer güvenlik avantajları sağlar, ancak yaygın olarak desteklenmez. - -DoT'yi kullanmak için cihazınızı bir DoT sunucusu kullanacak şekilde yapılandırmanız gerekir. DoT, Cloudflare, Quad9 ve Google dahil olmak üzere birkaç DNS sunucusu tarafından desteklenir. - -![https://www.myrasecurity.com/de/knowledge-hub/dns-over-tls (Erişim Tarihi: 07.04.2023)](/images/adguard/DNS-over-TLS.jpg) - -* ### 4.2.1 Dezavantajları - - * DoH gibi, DoT da güvenlik duvarları veya internet servis sağlayıcıları tarafından engellenebilir. Bu, özellikle ağ yöneticilerinin şifreli DNS sorgularına izin vermek istemediği ortamlarda kullanımı zorlaştırabilir. - - * DoT ile ilgili bir başka olası sorun, güvenlik duvarında açık olmak için özel bir bağlantı noktası (853 numaralı bağlantı noktası) gerektirmesidir. Güvenlik duvarı özellikle izin verilenler dışındaki tüm bağlantı noktalarını engelleyecek şekilde yapılandırılmışsa bu sorun olabilir. - -## 4.3 QUIC üzerinden DNS (DoQ) - -DNS-over-QUIC (DoQ), QUIC protokolünü kullanarak DNS sorgularını şifreleyen yeni bir protokoldür. DoQ hala geliştirme aşamasındadır, ancak DoH veya DoT'den daha hızlı ve daha güvenli DNS sorguları sağlama potansiyeline sahiptir. - -DoQ, gecikmeyi azaltan ve performansı artıran TCP yerine UDP kullanır. Ayrıca, bir DNS sunucusuyla bağlantı kurmak için gereken süreyi azaltabilen sıfır RTT anlaşmalarını da destekler. - -* ### 4.3.1 Dezavantajları - - * DoQ nispeten yeni bir protokoldür ve şu anda onu destekleyen yalnızca birkaç DNS sunucusu vardır. Bu, özellikle DoQ'yu desteklemeyen belirli bir DNS sunucusu kullanmanız gerekiyorsa, kullanımı zorlaştırabilir. - - * DoQ ile ilgili bir başka olası sorun, hala geliştirme aşamasında olması ve çözülmesi gereken hatalar veya uyumluluk sorunları olabilmesidir. Bu, daha yavaş performansa veya başka sorunlara neden olabilir. - -## 4.4 DNSCrypt - -DNSCrypt, DNS sorgularını ve yanıtlarını açık anahtarlı şifreleme kullanarak şifreleyen bir protokoldür. DNSCrypt, DNS sahtekarlığını ve ortadaki adam saldırılarını önlemek için tasarlanmıştır. - -DNSCrypt ile, DNS sorguları bir ortak anahtar kullanılarak şifrelenir ve sunucu, ortak anahtar kullanılarak doğrulanabilen imzalı bir yanıtla yanıt verir. Bu, saldırganların DNS sorgularını ve yanıtlarını yakalamasını ve manipüle etmesini önler. - -DNSCrypt, OpenDNS ve Cloudflare dahil olmak üzere birkaç DNS sunucusu tarafından desteklenir. Ayrıca, dnscrypt-proxy ve Simple DNSCrypt dahil olmak üzere birkaç DNS istemcisiyle birlikte kullanılabilir. - -![https://dev.to/cipherops/using-dnscrypt-with-adguard-home-pi-hole-7j6 (Erişim Tarihi: 07.04.2023)](/images/adguard/DNS-crypt.png) - -* ### 4.4.1 Dezavantajları - - * DNSCrypt'in olası bir dezavantajı, hem istemcinin hem de sunucunun protokolü desteklemesini gerektirmesidir. DNSCrypt birkaç DNS sunucusu ve istemcisi tarafından desteklenirken, DoH veya DoT kadar yaygın olarak desteklenmez. Bu, özellikle DNSCrypt'i desteklemeyen belirli bir DNS sunucusu kullanmanız gerekiyorsa, kullanımı zorlaştırabilir. - - * DNSCrypt ile ilgili bir başka olası sorun, gecikmeyi artırabilmesi ve DNS sorgularını yavaşlatabilmesidir. Bunun nedeni, DNSCrypt sorgularının, geleneksel bir DNS sorgusundan daha fazla ek yük gerektiren açık anahtarlı şifreleme kullanılarak şifrelenmesidir - -## > 4.5 Kısa Özet - -> (TL;DR) [^2] DNS-over-HTTPS, DNS-over-TLS, DNS-over-QUIC ve DNSCrypt birçok avantaj sağlarken, dikkate alınması gereken potansiyel dezavantajları da vardır. Bu protokoller, güvenlik duvarları veya internet servis sağlayıcıları tarafından engellenebilir ve gecikmeyi artırabilir veya DNS sorgularını yavaşlatabilir. Bu protokollerden herhangi birini kullanmadan önce, olası dezavantajları göz önünde bulundurmak ve ek güvenlik ve gizlilik avantajlarına değip değmeyeceğini belirlemek önemlidir. Ek olarak, tüm sunucular tüm protokolleri desteklemediğinden, kullandığınız DNS sunucusunun kullanmak istediğiniz protokolü desteklediğinden emin olmanız önemlidir. Seçtiğiniz protokol ne olursa olsun, güvenli bir DNS sunucusu kullanmak çevrimiçi gizliliğinizi ve güvenliğinizi korumada önemli bir adımdır. DNS sorgularınızın şifreli ve güvenli olduğundan emin olmak için bu protokollerden birini kullanmayı düşünün. ![https://www.researchgate.net/profile/Minzhao-Lyu/publication/357587121 (Erişim Tarihi: 07.04.2023)](/images/adguard/DNS-over-TLDR.png) - ----- - -# 5. Daha İleri Gizlilik İçin - -DNSSEC, EDNS İstemci Alt Ağı (ECS), Şifreli SNI (Encrypted SNI) ve Şifreli İstemci Merhaba (Encrypted Client Hello), internette güvenliği ve gizliliği geliştirmeye yardımcı olan önemli teknolojilerdir. Blog gönderimizin bu kısmında, söz konusu teknolojilerin her birine daha yakından bakacağız [^4] ve faydalarını keşfedeceğiz. - -[^4]: Dikkatli bakıyor musunuz? -Prestige [Youtube](https://www.youtube.com/watch?v=C6MlffsLfkM) - -## 5.1 DNSSEC - -DNSSEC, DNS sızdırma saldırılarını önlemek için tasarlanmış bir güvenlik protokolüdür. DNS sahtekarlığı, bir bilgisayar korsanı bir DNS sorgusunu yakaladığında ve istenen etki alanının IP adresini kötü amaçlı bir IP adresiyle değiştirdiğinde gerçekleşir. DNSSEC, DNS yanıtlarının gerçekliğini doğrulamak ve kullanıcıların doğru web sitesine yönlendirilmesini sağlamak için kriptografik imzalar kullanır. - -DNSSEC, her DNS kaydına, yanıta güvenmeden önce istekte bulunan cihaz tarafından doğrulanan bir dijital imza ekleyerek çalışır. DNSSEC ayrıca, orijinalliklerini doğrulamak için kullanılabilecek DNS kayıtları için ortak anahtarları dağıtmak için bir mekanizma sağlar. - -![https://www.dk-hostmaster.dk/en/dnssec (Erişim Tarihi: 07.04.2023)](/images/adguard/DNSSEC.png) - -## 5.2 EDNS İstemci Alt Ağı (ECS) - -EDNS İstemci Alt Ağı, DNS sunucularının istemcinin IP adresi hakkında bilgi almasına izin veren DNS protokolünün bir uzantısıdır. Bu bilgiler, DNS sorgularına daha doğru yanıtlar sağlamak için kullanılır ve DNS çözümleme sürecinin hızını ve güvenilirliğini artırmaya yardımcı olabilir. - -EDNS İstemci Alt Ağı ile DNS sunucuları, istekte bulunan cihazın coğrafi konumunu belirleyebilir ve bu konum için optimize edilmiş bir yanıt sağlayabilir. Bu, gecikmeyi azaltmaya ve internetin genel performansını iyileştirmeye yardımcı olabilir. - -## 5.3 Şifreli SNI (Encrypted SNI) - -Şifreli SNI (Server Name Indicator), TLS el sıkışma işleminde SNI alanını şifreleyen bir teknolojidir. SNI alanı, istemcinin bağlanmak istediği sunucunun ana bilgisayar adını belirlemek için kullanılır. Şifreli SNI, bu alanı şifreleyerek gizli dinleme ve ortadaki adam saldırılarını önlemeye yardımcı olur. - -Şifreli SNI, önemli bir gizlilik özelliğidir çünkü SNI alanı bir kullanıcının çevrimiçi etkinliğini izlemek için kullanılabilir. Şifreleme olmadan, ISP'ler, hükümetler ve diğer üçüncü tarafların SNI bilgilerine müdahale etmesi ve kullanıcı gizliliğini tehlikeye atarak izlemesi mümkündür. - -![https://blog.cloudflare.com/encrypted-client-hello (Erişim Tarihi: 07.04.2023)](/images/adguard/ESNI.png) - -## 5.4 Şifreli İstemci Merhaba (Encrypted Client Hello) - -Encrypted Client Hello, TLS anlaşma sürecinin gizliliğini ve güvenliğini artırmaya yardımcı olan başka bir teknolojidir. İstemci Merhaba mesajı, TLS bağlantısını başlatmak için istemci tarafından gönderilir ve istemcinin desteklediği TLS sürümleri ve şifre paketleri hakkında bilgi içerir. - -Encrypted Client Hello, İstemci Merhaba mesajını şifreleyerek, gizli dinleme ve ortadaki adam saldırılarını önlemeye yardımcı olur. Ayrıca, üçüncü tarafların Müşteri Merhaba mesajını ele geçirmesini ve analiz etmesini önleyerek kullanıcı gizliliğinin korunmasına yardımcı olur. - -![https://blog.cloudflare.com/encrypted-client-hello (Erişim Tarihi: 07.04.2023)](/images/adguard/ECH.png) - -Çözüm -DNSSEC, EDNS İstemci Alt Ağı, Şifreli SNI ve Şifreli İstemci Hello, internette güvenliği ve gizliliği geliştirmeye yardımcı olan önemli teknolojilerdir. Bu teknolojiler, DNS sahtekarlığı saldırılarını önlemek, daha doğru DNS yanıtları sağlamak ve TLS el sıkışma işlemi sırasında kullanıcı gizliliğini korumak için tasarlanmıştır. Bu teknolojileri uygulayarak herkes için daha güvenli ve güvenli bir internet oluşturmaya yardımcı olabiliriz. - ----- - -# 6. Sonuç - -(TL;DR) İnternette gezinirken karşınıza çıkan reklamlardan sıkıldıysanız, AdGuard reklamları engellemek için mükemmel bir seçimdir. Gelişmiş özellikleri ve özelleştirilebilir filtreleri, size hangi içeriği görüp neyi görmediğiniz üzerinde tam kontrol sağlar. AdGuard'ı bugün indirin ve daha hızlı, daha güvenli ve daha keyifli bir tarama deneyiminin keyfini çıkarın. +--- +title: "AdGuard ile Reklam Engelleme" +date: 2023-04-06 +tags: ["windows", "ad", "adblock", "adguard", "youtubeads", "youtube", "dns", "doh", "dns-over-https", "dns-over-tls", "dns-over-Quic", "DNSSEC", "DNS-crypt","ESNI", "Encryted SNI", "ECH", "Encrypted Client Hello"] +author: "Wise" +draft: false +--- +# 1. AdGuard: Reklamsız Gezinti İçin Nihai Çözümünüz + +İnternette gezinirken sürekli karşınıza çıkan reklam ve açılır pencerelerinden sıkıldıysanız, [AdGuard Windows uygulamasını](https://adguard.com/tr/adguard-windows/overview.html) kullanmayı düşünebilirsiniz. AdGuard, yalnızca reklamları kaldırmakla kalmayıp aynı zamanda bilgisayarınızı kötü amaçlı yazılımlardan ve kimlik avı saldırılarından koruyan güçlü bir reklam engelleyicidir. Tanıdığınız ve bildiğiniz tüm reklamlara son kez sarılın artık onları bir daha göremeyeceksiniz. Çünkü bu blog gönderisinde, AdGuard'ın özelliklerini ve göz atma deneyiminizi nasıl geliştirebileceğini keşfedeceğiz. + +## 1.1 AdGuard Uygulamasının Özellikleri + +### 1.1.1 Reklam engelleyici + +* AdGuard'ın birincil özelliği, banner reklamlar, açılır pencereler ve video reklamlar dahil olmak üzere her türlü reklamı[^1] web sayfalarından kaldırabilen reklam engelleyicisidir. Bu özellik yalnızca gezinmeyi hızlandırmakla kalmaz, aynı zamanda verilerden tasarruf etmenizi sağlar ve göz yorgunluğunu azaltır. + +[^1]: `Contextual Advertising`, `Analytics Tools`, `Banner Advertising`, `Error Monitoring`, `Cookie Consent Notification`, `Youtube Ads` ve `Message Box` + +### 1.1.2 Gizlilik koruması + +* AdGuard, web sitelerinin verilerinizi toplamak için kullandığı izleme çerezlerini ve diğer izleme mekanizmalarını engelleyerek gizliliğinizi korur. Ayrıca, IP adresinizi ve diğer hassas bilgileri web sitelerinden gizleyen Gizli mod adı verilen bir özelliği de vardır. + +### 1.1.3 Ebeveyn Kontrolü + +* AdGuard, yetişkinlere uygun içerik veya diğer uygunsuz materyaller barındıran web sitelerine erişimi engellemenizi sağlayan bir ebeveyn denetimi özelliğine sahiptir. Belirli web sitelerini veya kategorileri engellemek için özel kurallar da oluşturabilirsiniz. + +### 1.1.4 Malware koruması + +* AdGuard, kötü amaçlı kod veya bağlantılar içeren web sitelerini engelleyen yerleşik bir kötü amaçlı yazılımdan koruma özelliğine sahiptir. Ayrıca tehlikeli olduğu bildirilen bir web sitesini ziyaret ettiğinizde sizi uyarabilir. + +### 1.1.5 Özelleştirilebilir Filtreler + +* AdGuard, belirli içerik türlerini veya web sitelerini engellemek için kendi filtrelerinizi oluşturmanıza veya diğer kullanıcılardan filtreler eklemenize olanak tanır. Bu özellik, gördükleriniz ve görmedikleriniz üzerinde tam kontrol sahibi olmanızı sağlar. + +### 1.1.6 Kullanıcı dostu arayüz + +* AdGuard, en acemi kullanıcılar için bile kullanımı kolaylaştıran basit ve sezgisel bir arayüze sahiptir. Tüm özelliklere ve ayarlara ana panodan kolayca erişebilirsiniz. + +### > 1.1.7 Kısa Özet + +> (TL;DR)[^2] AdGuard karşınıza çıkan reklamları engellerken aynı zamanda da kullanıcı dostu arayüzü ve özelleştirilebilir filtreleri sayesinde gizliliğinizi de korur. Ebeveyn kontrolü ve Malware koruması sayesinde ise istenmeyen sonuçlara karşı hazırlıklı olursunuz. + +[^2]: TL;DR: `Too long; Didn't read` veya `Çok uzundu; okumadım` özet geç anlamında + +## 1.2 Neden AdGuard'ı Seçmelisiniz? + +AdGuard, gelişmiş özellikleri ve kullanımı kolay arayüzü nedeniyle Windows için mevcut olan en iyi reklam engelleyicilerden biridir. İşte AdGuard'ı seçmeniz için bazı nedenler: + +### 1.2.1 Kapsamlı Reklam Engelleme + +* AdGuard, pop-up'lar, video reklamlar ve banner reklamlar dahil her türlü reklamı[^1] engelleyerek tarama deneyiminizi daha akıcı ve hızlı hale getirebilir. + +### 1.2.2 Gelişmiş Gizlilik Koruması + +* AdGuard yalnızca reklamları engellemekle kalmaz, izleme çerezlerini engelleyerek ve IP adresinizi gizleyerek gizliliğinizi de korur. + +### 1.2.3 Malware koruması + +* AdGuard'ın kötü amaçlı yazılımdan koruma özelliği, sizi kötü amaçlı web sitelerinden korur ve tehlikeli bir siteyi ziyaret ettiğinizde sizi uyarır. + +### 1.2.4 Özelleştirilebilir Filtreler + +* AdGuard'ın özelleştirilebilir filtreleri, size hangi içeriği görüp neyi görmediğiniz konusunda tam kontrol sağlar. + +### 1.2.5 Kullanımı Kolay Arayüz + +* AdGuard'ın kullanıcı dostu arayüzü, teknik uzmanlıkları ne olursa olsun tüm kullanıcılar için kullanımı kolaylaştırır. + +### > 1.2.6 Kısa Özet + +> (TL;DR) [^2] AdGuard diğer reklam engelleme yazılımları ve çözümlerinden daha gelişmiş ve hızlı bir çözüme sahiptir. Ayrıca diğer yazılımlarda olmayan Malware koruması ve Gelişmiş Gizlilik özelliklerine de sahiptir. + +---- + +# 2. AdGuard Windows Uygulaması Nasıl Kurulur + +AdGuard, bilgisayarınızı kötü amaçlı yazılımlardan ve kimlik avı saldırılarından koruyabilen ve aynı zamanda web sayfalarından her türlü reklamı[^1] kaldırabilen güçlü bir reklam engelleyicidir. Reklamsız bir tarama deneyimi yaşamak istiyorsanız, AdGuard'ı Windows PC'nize yüklemek kolay ve kolaydır. Bu blog gönderisinde, AdGuard'ı Windows PC'nize yükleme adımlarında size rehberlik edeceğiz. + +## 2.1 Adım Adım Kılavuz + +### 2.1.1 AdGuard Yükleyiciyi İndirin + +AdGuard'ı Windows PC'nize kurmanın ilk adımı, AdGuard yükleyicisini resmi web sitesinden indirmektir. AdGuard web sitesindeki "İndir" düğmesine tıklayarak yükleyiciyi indirebilirsiniz. + +![https://adguard.com/tr/adguard-windows/overview.html (Erişim Tarihi 07.04.2023)](/images/adguard/1.jpg) + +### 2.1.2 Yükleyiciyi Çalıştırın + +AdGuard yükleyicisini indirdikten sonra, PC'nizde dosyayı bulun ve yükleyiciyi çalıştırmak için üzerine çift tıklayın. Kullanıcı Hesabı Denetimi (UAC) tarafından istenirse, yükleyiciye PC'nizde değişiklik yapması için izin vermeniz gerekebilir. + +![Adguard Windows uygulaması yükleyici görüntüleri](/images/adguard/2.png) + +### 2.1.3 Kurulum Seçeneklerini Seçin + +Bir sonraki adım, AdGuard için kurulum seçeneklerini seçmektir. AdGuard'ı tüm kullanıcılar için veya yalnızca mevcut kullanıcı için yüklemeyi seçebilirsiniz. Ayrıca kurulum klasörünü seçebilir ve bir masaüstü kısayolu oluşturabilirsiniz. + +![Adguard Windows uygulaması kurulum seçenekleri](/images/adguard/3.png) + +### 2.1.4 AdGuard'ı yükleyin + +Kurulum seçeneklerini seçtikten sonra, kurulum sürecini başlatmak için "Yükle" düğmesine tıklayın. Yükleme işlemi bilgisayarınızın hızına bağlı olarak birkaç dakika sürebilir. + +![Adguard Windows uygulaması kurulum görüntüleri](/images/adguard/4.png) + +### 2.1.5 AdGuard'ı başlatın + +Yükleme tamamlandıktan sonra, AdGuard'ı masaüstü kısayolundan veya Başlat menüsünden başlatabilirsiniz. AdGuard'ı ilk kez başlattığınızda, ayarları tercihlerinize göre yapılandırmanızı isteyecektir. + +![Adguard Windows uygulaması genel ayarları](/images/adguard/5.jpg) + +### 2.1.6 Reklamsız Taramanın Keyfini Çıkarın + +AdGuard'ın ayarlarını yapılandırdıktan sonra, reklamsız bir göz atma deneyiminin keyfini çıkarabilirsiniz. AdGuard, web sayfalarından her türlü reklamı[^1] otomatik olarak kaldırarak gezinmenizi daha hızlı ve sorunsuz hale getirir. + +![https://www.youtube.com/watch?v=YW9Ojcm1Gkg (Erişim Tarihi 07.04.2023)](/images/adguard/6.jpg) + +### > 2.1.7 Kısa Özet + +> Sistem admini iseniz veya herhangi bir ayar ile uğraşmaadan direk kurmak istiyorsanız `Msiexec /q /i AdGuard.msi` komutunu kullanabilirsiniz. +> +> Alternatif olarak da halk arasında "Next > Next > Next" tabir edilen yöntemi kullanabilirsiniz. Yani `kapattım gözlerimi karanlığa, açtım ellerimi sonsuzluğa, rabbim sonum hayrola :D` diyerek her gelen sayfada hiçbir şeyi okumadan İleri/Next butonuna tıklayarak çok hızlı bir şekilde kurabilirsiniz. +---- + +# 3. AdGuard Nasıl Çalışıyor? + +AdGuard, dünya çapında milyonlarca kullanıcının güvendiği güçlü bir reklam engelleyicidir. Reklamları engelleme yollarından biri, DNS tabanlı engelleme teknikleri kullanmaktır. Bu blog gönderisinde, AdGuard'ın DNS, DNS-over-HTTPS (DoH) ve diğer teknikleri kullanarak reklamları nasıl engellediğini keşfedeceğiz. + +## 3.1 DNS Tabanlı Engelleme + +DNS tabanlı engelleme, AdGuard tarafından reklamları DNS isteklerini kara listeye alınmış bir IP adresine yönlendirerek engellemek için kullanılan bir tekniktir. Bir web sitesini ziyaret ettiğinizde, tarayıcınız, web sitesinin alan adını bir IP adresine çevirmek için bir DNS sunucusuna bir DNS isteği gönderir. AdGuard bu isteği yakalar ve kara listesine göre kontrol eder. Alan kara listedeyse AdGuard, isteği kara listedeki bir IP adresine yönlendirerek reklamın ekranınızda görüntülenmesini etkili bir şekilde engeller. + +DNS filtresi, reklamları daha bilgisayarınıza yüklenmelerine fırsat vermeden engelleyerek zamandan ve bant genişliğinden tasarruf etmenizi sağladığı için oldukça etkilidir. AdGuard'ın DNS filtresi de son derece özelleştirilebilir olup, kullanıcıların gerektiğinde belirli alanları beyaz listeye veya kara listeye almasına olanak tanır. DNS tabanlı engelleme, reklamları engellemenin basit ve etkili bir yoludur, ancak bazı sınırlamaları vardır. Örneğin, bazı reklamlar, standart olmayan bağlantı noktaları veya şifreli bağlantılar kullanarak DNS engellemesini atlayabilir. + +## 3.2 HTTPS filtresi + +HTTPS filtresi, AdGuard'ın bir başka önemli özelliğidir ve HTTPS şifrelemesi kullanan web sitelerindeki istenmeyen içeriği filtreleyerek çalışır. Birçok reklam engelleme aracı, şifreleme web sitesinin içeriğini görmelerini engellediği için HTTPS web sitelerindeki reklamları engellemekte zorlanır. Ancak, AdGuard'ın HTTPS filtresi, web sitesinin içeriğinin şifresini çözebilir ve istenmeyen reklamları veya diğer içeriği filtreleyebilir. + +HTTPS filtresi, daha fazla web sitesi gelişmiş güvenlik için HTTPS'ye geçtikçe giderek yaygınlaşan HTTPS şifrelemesi kullanan web sitelerindeki reklamları engellemede oldukça etkilidir. AdGuard'ın HTTPS filtresi de son derece özelleştirilebilir ve kullanıcıların belirli web sitelerini veya etki alanlarını beyaz veya kara listeye almasına olanak tanır. + +## 3.3 İçerik filtresi + +İçerik filtresi, AdGuard'ın bir diğer önemli özelliğidir ve web sitelerindeki istenmeyen içeriği filtreleyerek çalışır. Buna, kullanıcıların dikkatini dağıtabilecek veya rahatsız edebilecek reklamlar, açılır pencereler, Cookie (Çerez) uyarı bildirimleri, afişler ve diğer istenmeyen içerik türleri dahildir. + +İçerik filtresi, tüm etki alanlarını veya IP adreslerini engellemek yerine bir web sitesindeki belirli öğeleri hedef aldığı için oldukça etkilidir. Bu, kullanıcıların istenmeyen içerikle bombardımana tutulmadan daha akıcı bir tarama deneyiminin keyfini çıkarmasına olanak tanır. AdGuard'ın İçerik filtresi de son derece özelleştirilebilir ve kullanıcıların belirli web sitelerini veya etki alanlarını beyaz veya kara listeye almasına olanak tanır. + +## > 3.4 Kısa Özet + +> (TL;DR) [^2] ![https://adguard.com/tr/adguard-windows/overview.html (Erişim Tarihi: 07.04.2023)](/images/adguard/adguard-nasil-calisir.jpg) + +---- + +# 4. DNS ile ilgili Gelişmiş Ayalar + +DNS (Alan Adı Sistemi), insanlar tarafından okunabilen alan adlarını bilgisayarların anlayabileceği IP adreslerine çevirmek için kullanılan bir protokoldür. Ancak, DNS sorguları normal olarak 53 numaralı port üzerinden gönderilir ve herhangi bir şifreleme yapılmaz. Dolayısıyla varsayılan olarak güvenli değildir ve DNS sorguları saldırganlar tarafından ele geçirilebilir veya manipüle edilebilir. + +![https://blog.chromium.org/2020/05/a-safer-and-more-private-browsing-DoH.html (Erişim Tarihi: 07.04.2023)](/images/adguard/Unsecured-DNS.png) + +Bu sorunu çözmek için HTTPS üzerinden DNS (DoH), TLS üzerinden DNS (DoT), QUIC üzerinden DNS (DoQ) ve DNSCrypt dahil olmak üzere birkaç yeni protokol geliştirilmiştir. Blog gönderisinin bu kısmında, bu protokoller arasındaki farkları ve DNS sorgularınızı korumaya nasıl yardımcı olabileceklerini tartışacağız. DNS-over-HTTPS (DoH), DNS-over-TLS (DoT), DNS-over-QUIC (DoQ) ve DNSCrypt birçok avantaj sağlarken, dikkate alınması gereken bazı potansiyel dezavantajlar da vardır. [^3] + +[^3]: Büyük güç büyük sorumluluk getirir. -Örümcek Adam + +## 4.1 HTTPS üzerinden DNS (DoH) + +DNS-over-HTTPS (DoH), HTTPS protokolünü kullanarak DNS sorgularını şifreleyen bir protokoldür. DoH, üçüncü tarafların DNS sorgularına müdahale etmesini ve kurcalamasını önleyerek gizliliği ve güvenliği artırmak için tasarlanmıştır. DoH ile, DNS sorguları şifrelenmiş bir kanal üzerinden gönderilerek saldırganların bunları yakalamasını ve manipüle etmesini zorlaştırır. + +DoH, Firefox, Chrome ve Edge dahil olmak üzere birçok büyük web tarayıcısı tarafından desteklenir. Bir DoH uygulaması yükleyerek veya cihazınızı bir DoH sunucusu kullanacak şekilde yapılandırarak mobil cihazlarda da kullanılabilir. + +![https://blog.chromium.org/2020/05/a-safer-and-more-private-browsing-DoH.html (Erişim Tarihi: 07.04.2023)](/images/adguard/DNS-over-HTTPS.png) + +* ### 4.1.1 Dezavantajları + + * DoH'nin bir dezavantajı, belirli ortamlarda uygulanmasının zor olabilmesidir. Örneğin DoH, bazı güvenlik duvarları veya internet servis sağlayıcıları tarafından engellenebilir ve bu da kullanımını zorlaştırabilir. Ek olarak, bazı ağ yöneticileri, ağ trafiğini izlemeyi ve denetlemeyi zorlaştırabileceğinden, şifrelenmiş DNS sorgularına izin vermek istemeyebilir. + + * DoH ile ilgili bir başka olası sorun, gecikmeyi artırabilmesi ve DNS sorgularını yavaşlatabilmesidir. Bunun nedeni, DoH sorgularının, geleneksel bir DNS sorgusundan daha fazla ek yük gerektiren bir HTTPS bağlantısı üzerinden gönderilmesidir. Bu, çoğu kullanıcı için fark edilmese de, çevrimiçi oyunlar veya gerçek zamanlı video konferans gibi düşük gecikmeli DNS sorguları gerektiren uygulamalar için bir sorun olabilir. + +## 4.2 TLS üzerinden DNS (DoT) + +DNS-over-TLS (DoT), DNS sorgularını şifreleyen başka bir protokoldür, ancak HTTPS yerine Aktarım Katmanı Güvenliği (TLS) protokolünü kullanır. DoT, DoH ile benzer güvenlik avantajları sağlar, ancak yaygın olarak desteklenmez. + +DoT'yi kullanmak için cihazınızı bir DoT sunucusu kullanacak şekilde yapılandırmanız gerekir. DoT, Cloudflare, Quad9 ve Google dahil olmak üzere birkaç DNS sunucusu tarafından desteklenir. + +![https://www.myrasecurity.com/de/knowledge-hub/dns-over-tls (Erişim Tarihi: 07.04.2023)](/images/adguard/DNS-over-TLS.jpg) + +* ### 4.2.1 Dezavantajları + + * DoH gibi, DoT da güvenlik duvarları veya internet servis sağlayıcıları tarafından engellenebilir. Bu, özellikle ağ yöneticilerinin şifreli DNS sorgularına izin vermek istemediği ortamlarda kullanımı zorlaştırabilir. + + * DoT ile ilgili bir başka olası sorun, güvenlik duvarında açık olmak için özel bir bağlantı noktası (853 numaralı bağlantı noktası) gerektirmesidir. Güvenlik duvarı özellikle izin verilenler dışındaki tüm bağlantı noktalarını engelleyecek şekilde yapılandırılmışsa bu sorun olabilir. + +## 4.3 QUIC üzerinden DNS (DoQ) + +DNS-over-QUIC (DoQ), QUIC protokolünü kullanarak DNS sorgularını şifreleyen yeni bir protokoldür. DoQ hala geliştirme aşamasındadır, ancak DoH veya DoT'den daha hızlı ve daha güvenli DNS sorguları sağlama potansiyeline sahiptir. + +DoQ, gecikmeyi azaltan ve performansı artıran TCP yerine UDP kullanır. Ayrıca, bir DNS sunucusuyla bağlantı kurmak için gereken süreyi azaltabilen sıfır RTT anlaşmalarını da destekler. + +* ### 4.3.1 Dezavantajları + + * DoQ nispeten yeni bir protokoldür ve şu anda onu destekleyen yalnızca birkaç DNS sunucusu vardır. Bu, özellikle DoQ'yu desteklemeyen belirli bir DNS sunucusu kullanmanız gerekiyorsa, kullanımı zorlaştırabilir. + + * DoQ ile ilgili bir başka olası sorun, hala geliştirme aşamasında olması ve çözülmesi gereken hatalar veya uyumluluk sorunları olabilmesidir. Bu, daha yavaş performansa veya başka sorunlara neden olabilir. + +## 4.4 DNSCrypt + +DNSCrypt, DNS sorgularını ve yanıtlarını açık anahtarlı şifreleme kullanarak şifreleyen bir protokoldür. DNSCrypt, DNS sahtekarlığını ve ortadaki adam saldırılarını önlemek için tasarlanmıştır. + +DNSCrypt ile, DNS sorguları bir ortak anahtar kullanılarak şifrelenir ve sunucu, ortak anahtar kullanılarak doğrulanabilen imzalı bir yanıtla yanıt verir. Bu, saldırganların DNS sorgularını ve yanıtlarını yakalamasını ve manipüle etmesini önler. + +DNSCrypt, OpenDNS ve Cloudflare dahil olmak üzere birkaç DNS sunucusu tarafından desteklenir. Ayrıca, dnscrypt-proxy ve Simple DNSCrypt dahil olmak üzere birkaç DNS istemcisiyle birlikte kullanılabilir. + +![https://dev.to/cipherops/using-dnscrypt-with-adguard-home-pi-hole-7j6 (Erişim Tarihi: 07.04.2023)](/images/adguard/DNS-crypt.png) + +* ### 4.4.1 Dezavantajları + + * DNSCrypt'in olası bir dezavantajı, hem istemcinin hem de sunucunun protokolü desteklemesini gerektirmesidir. DNSCrypt birkaç DNS sunucusu ve istemcisi tarafından desteklenirken, DoH veya DoT kadar yaygın olarak desteklenmez. Bu, özellikle DNSCrypt'i desteklemeyen belirli bir DNS sunucusu kullanmanız gerekiyorsa, kullanımı zorlaştırabilir. + + * DNSCrypt ile ilgili bir başka olası sorun, gecikmeyi artırabilmesi ve DNS sorgularını yavaşlatabilmesidir. Bunun nedeni, DNSCrypt sorgularının, geleneksel bir DNS sorgusundan daha fazla ek yük gerektiren açık anahtarlı şifreleme kullanılarak şifrelenmesidir + +## > 4.5 Kısa Özet + +> (TL;DR) [^2] DNS-over-HTTPS, DNS-over-TLS, DNS-over-QUIC ve DNSCrypt birçok avantaj sağlarken, dikkate alınması gereken potansiyel dezavantajları da vardır. Bu protokoller, güvenlik duvarları veya internet servis sağlayıcıları tarafından engellenebilir ve gecikmeyi artırabilir veya DNS sorgularını yavaşlatabilir. Bu protokollerden herhangi birini kullanmadan önce, olası dezavantajları göz önünde bulundurmak ve ek güvenlik ve gizlilik avantajlarına değip değmeyeceğini belirlemek önemlidir. Ek olarak, tüm sunucular tüm protokolleri desteklemediğinden, kullandığınız DNS sunucusunun kullanmak istediğiniz protokolü desteklediğinden emin olmanız önemlidir. Seçtiğiniz protokol ne olursa olsun, güvenli bir DNS sunucusu kullanmak çevrimiçi gizliliğinizi ve güvenliğinizi korumada önemli bir adımdır. DNS sorgularınızın şifreli ve güvenli olduğundan emin olmak için bu protokollerden birini kullanmayı düşünün. ![https://www.researchgate.net/profile/Minzhao-Lyu/publication/357587121 (Erişim Tarihi: 07.04.2023)](/images/adguard/DNS-over-TLDR.png) + +---- + +# 5. Daha İleri Gizlilik İçin + +DNSSEC, EDNS İstemci Alt Ağı (ECS), Şifreli SNI (Encrypted SNI) ve Şifreli İstemci Merhaba (Encrypted Client Hello), internette güvenliği ve gizliliği geliştirmeye yardımcı olan önemli teknolojilerdir. Blog gönderimizin bu kısmında, söz konusu teknolojilerin her birine daha yakından bakacağız [^4] ve faydalarını keşfedeceğiz. + +[^4]: Dikkatli bakıyor musunuz? -Prestige [Youtube](https://www.youtube.com/watch?v=C6MlffsLfkM) + +## 5.1 DNSSEC + +DNSSEC, DNS sızdırma saldırılarını önlemek için tasarlanmış bir güvenlik protokolüdür. DNS sahtekarlığı, bir bilgisayar korsanı bir DNS sorgusunu yakaladığında ve istenen etki alanının IP adresini kötü amaçlı bir IP adresiyle değiştirdiğinde gerçekleşir. DNSSEC, DNS yanıtlarının gerçekliğini doğrulamak ve kullanıcıların doğru web sitesine yönlendirilmesini sağlamak için kriptografik imzalar kullanır. + +DNSSEC, her DNS kaydına, yanıta güvenmeden önce istekte bulunan cihaz tarafından doğrulanan bir dijital imza ekleyerek çalışır. DNSSEC ayrıca, orijinalliklerini doğrulamak için kullanılabilecek DNS kayıtları için ortak anahtarları dağıtmak için bir mekanizma sağlar. + +![https://www.dk-hostmaster.dk/en/dnssec (Erişim Tarihi: 07.04.2023)](/images/adguard/DNSSEC.png) + +## 5.2 EDNS İstemci Alt Ağı (ECS) + +EDNS İstemci Alt Ağı, DNS sunucularının istemcinin IP adresi hakkında bilgi almasına izin veren DNS protokolünün bir uzantısıdır. Bu bilgiler, DNS sorgularına daha doğru yanıtlar sağlamak için kullanılır ve DNS çözümleme sürecinin hızını ve güvenilirliğini artırmaya yardımcı olabilir. + +EDNS İstemci Alt Ağı ile DNS sunucuları, istekte bulunan cihazın coğrafi konumunu belirleyebilir ve bu konum için optimize edilmiş bir yanıt sağlayabilir. Bu, gecikmeyi azaltmaya ve internetin genel performansını iyileştirmeye yardımcı olabilir. + +## 5.3 Şifreli SNI (Encrypted SNI) + +Şifreli SNI (Server Name Indicator), TLS el sıkışma işleminde SNI alanını şifreleyen bir teknolojidir. SNI alanı, istemcinin bağlanmak istediği sunucunun ana bilgisayar adını belirlemek için kullanılır. Şifreli SNI, bu alanı şifreleyerek gizli dinleme ve ortadaki adam saldırılarını önlemeye yardımcı olur. + +Şifreli SNI, önemli bir gizlilik özelliğidir çünkü SNI alanı bir kullanıcının çevrimiçi etkinliğini izlemek için kullanılabilir. Şifreleme olmadan, ISP'ler, hükümetler ve diğer üçüncü tarafların SNI bilgilerine müdahale etmesi ve kullanıcı gizliliğini tehlikeye atarak izlemesi mümkündür. + +![https://blog.cloudflare.com/encrypted-client-hello (Erişim Tarihi: 07.04.2023)](/images/adguard/ESNI.png) + +## 5.4 Şifreli İstemci Merhaba (Encrypted Client Hello) + +Encrypted Client Hello, TLS anlaşma sürecinin gizliliğini ve güvenliğini artırmaya yardımcı olan başka bir teknolojidir. İstemci Merhaba mesajı, TLS bağlantısını başlatmak için istemci tarafından gönderilir ve istemcinin desteklediği TLS sürümleri ve şifre paketleri hakkında bilgi içerir. + +Encrypted Client Hello, İstemci Merhaba mesajını şifreleyerek, gizli dinleme ve ortadaki adam saldırılarını önlemeye yardımcı olur. Ayrıca, üçüncü tarafların Müşteri Merhaba mesajını ele geçirmesini ve analiz etmesini önleyerek kullanıcı gizliliğinin korunmasına yardımcı olur. + +![https://blog.cloudflare.com/encrypted-client-hello (Erişim Tarihi: 07.04.2023)](/images/adguard/ECH.png) + +Çözüm +DNSSEC, EDNS İstemci Alt Ağı, Şifreli SNI ve Şifreli İstemci Hello, internette güvenliği ve gizliliği geliştirmeye yardımcı olan önemli teknolojilerdir. Bu teknolojiler, DNS sahtekarlığı saldırılarını önlemek, daha doğru DNS yanıtları sağlamak ve TLS el sıkışma işlemi sırasında kullanıcı gizliliğini korumak için tasarlanmıştır. Bu teknolojileri uygulayarak herkes için daha güvenli ve güvenli bir internet oluşturmaya yardımcı olabiliriz. + +---- + +# 6. Sonuç + +(TL;DR) İnternette gezinirken karşınıza çıkan reklamlardan sıkıldıysanız, AdGuard reklamları engellemek için mükemmel bir seçimdir. Gelişmiş özellikleri ve özelleştirilebilir filtreleri, size hangi içeriği görüp neyi görmediğiniz üzerinde tam kontrol sağlar. AdGuard'ı bugün indirin ve daha hızlı, daha güvenli ve daha keyifli bir tarama deneyiminin keyfini çıkarın. diff --git a/content/post/crowdsec-anlatim.md b/content/post/crowdsec-anlatim.md index 29972ce6..1aa86781 100644 --- a/content/post/crowdsec-anlatim.md +++ b/content/post/crowdsec-anlatim.md @@ -1,320 +1,320 @@ ---- -title: "Crowdsec IPS/IDS Yazılımı" -date: 2023-04-11 -tags: ["linux", "bot", "botnet", "dos", "ddos", "crowdsec", "ıps", "ids", "parser", "scenario", "data source", "ban", "captcha","ip", "asn", "subnet", "ip block"] -author: "Wise" -draft: false ---- -# 1. Crowdsec IPS/IDS Yazılımı Tanıtımı - -CrowdSec, siber tehditlere karşı gerçek zamanlı koruma sağlamak için kolektif bir zeka yaklaşımı kullanan Linux sunucuları için açık kaynaklı bir güvenlik çözümüdür. Bu blog gönderisinde, CrowdSec'in (v.1.4.6)[^1] özelliklerini, Linux sunucularınızı korumak için neden harika bir seçim olduğunun nedenlerini ve CrowdSec ile diğer IPS/IDS yazılımları arasındaki farkları ve benzerlikleri keşfedeceğiz. - -[^1]: https://github.com/crowdsecurity/crowdsec/releases/tag/v1.4.6 - -## 1.1 CrowdSec'in Özellikleri - -CrowdSec, onu Linux sunucuları için güçlü ve etkili bir güvenlik çözümü yapan çeşitli özellikler sunar. Temel özelliklerinden bazıları şunlardır: - -### 1.1.1 Gerçek zamanlı tehdit tespiti - -* CrowdSec, tehditleri gerçek zamanlı olarak tespit etmek için makine öğrenimi algoritmalarını kullanır ve saldırıların gerçekleşmesini önler. - -### 1.1.2 Otomatik engelleme - -* Bir tehdit algılandığında CrowdSec, saldırıyla ilişkili IP adresini otomatik olarak engelleyerek anında koruma sağlar. - -### 1.1.3 Kolektif zeka - -* CrowdSec, yeni ve gelişmekte olan tehditleri algılamak için diğer CrowdSec kullanıcıları da dahil olmak üzere birden çok kaynaktan gelen verilerden yararlanır. - -### 1.1.4 Kolay entegrasyon - -* CrowdSec, kapsamlı bir güvenlik çözümü sağlamak için güvenlik duvarları ve SIEM'ler gibi diğer güvenlik çözümleriyle kolayca entegre edilebilir. - -### 1.1.5 Özelleştirilebilir kurallar - -* CrowdSec, kullanıcıların güvenlik politikalarının kendi özel gereksinimleriyle uyumlu olmasını sağlayarak kendi kurallarını oluşturmasına ve özelleştirmesine olanak tanır. - -## 1.2 Neden CrowdSec'i Seçmelisiniz? - -CrowdSec'in Linux sunucularınızın güvenliğini sağlamak için mükemmel bir seçim olmasının birkaç nedeni vardır. Bu nedenlerden bazıları şunlardır: - -### 1.2.1 Açık kaynak - -* CrowdSec açık kaynaklı bir çözümdür, yani kullanımı ücretsizdir ve özel ihtiyaçlarınızı karşılayacak şekilde kolayca özelleştirilebilir. - -### 1.2.2 Toplu zeka - -* CrowdSec, yeni ve gelişmekte olan tehditleri tespit etmek için toplu zekanın gücünden yararlanarak geleneksel güvenlik çözümlerinden daha yüksek düzeyde koruma sağlar. - -### 1.2.3 Kolay entegrasyon - -* CrowdSec, diğer güvenlik çözümleriyle kolayca entegre edilebilir ve bu da onu her kuruluş için esnek ve uyarlanabilir bir çözüm haline getirir. - -### 1.2.4 Özelleştirilebilir kurallar - -* CrowdSec, kullanıcıların güvenlik politikalarının kendi özel gereksinimleriyle uyumlu olmasını sağlayarak kendi kurallarını oluşturmasına ve özelleştirmesine olanak tanır. - -## 1.3 CrowdSec ve Cloudflare Arasındaki Fark ve Benzerlikler - -CrowdSec ve Cloudflare güvenlik çözümleri olmakla birlikte, ikisi arasında bazı temel farklılıklar vardır. Örneğin: - -### 1.3.1 Farkları - -* CrowdSec açık kaynaklı bir çözümken Cloudflare ticari bir çözümdür. - -* CrowdSec, yeni ve gelişmekte olan tehditleri algılamak için toplu zekayı kullanırken Cloudflare, makine öğrenimi ve imza tabanlı algılamanın bir kombinasyonunu kullanır. - -* CrowdSec, Linux sunucularını korumaya odaklanırken, Cloudflare çok çeşitli platformlar için güvenlik çözümleri sunar. - -### 1.3.2 Benzerlikleri - -Bu farklılıklara rağmen, hem CrowdSec hem de Cloudflare bazı benzerlikleri paylaşır. Örneğin: - -* Her iki çözüm de tehditleri gerçek zamanlı olarak algılamak için makine öğrenimi algoritmalarını kullanır. - -* Her iki çözüm de kötü amaçlı IP adreslerinin otomatik olarak engellenmesini sağlar. - -* Her iki çözüm de diğer güvenlik çözümleriyle kolayca entegre edilebilir ve kapsamlı bir güvenlik çözümü sunar. - -## 1.4 Kısa Özet - -(TL;DR) [^2] CrowdSec, Linux sunucuları için gerçek zamanlı tehdit algılama, otomatik engelleme ve toplu zeka sağlayan güçlü ve etkili bir güvenlik çözümüdür. Açık kaynak yapısı, kolay entegrasyonu ve özelleştirilebilir kuralları, onu Linux sunucularının güvenliğini sağlamak isteyen tüm kuruluşlar için mükemmel bir seçim haline getirir. CrowdSec ve Cloudflare arasında bazı farklılıklar olsa da, her iki çözüm de bazı benzerliklere sahiptir ve dijital varlıklarını güvence altına almak isteyen kuruluşlar için mükemmel seçeneklerdir. - -[^2]: TL;DR: `Too long; Didn't read` veya `Çok uzundu; okumadım` özet geç anlamında - -# 2. Crowdsec Linux Nasıl Kurulur - -CrowdSec, siber tehditlere karşı gerçek zamanlı koruma sağlamak için toplu zeka kullanan Linux sunucuları için açık kaynaklı bir güvenlik çözümüdür. Blog yazısının bu kısmında CrowdSec'i Linux sunucunuza kurma adımlarının yanı sıra sunucunuzun güvenliğini daha da artırmak için bir Linux bouncer'ı nasıl kuracağınız konusunda size yol göstereceğiz. - -## 2.1 Adım Adım Kılavuz - -Başlamadan önce, kurulum işleminin Linux dağıtımınıza bağlı olarak değişebileceğini lütfen unutmayın. Aşağıdaki adımlar Ubuntu 20.04'ü temel alır, ancak diğer dağıtımlar için talimatları CrowdSec dokümantasyon sayfasında bulabilirsiniz. - -### 2.1.1 CrowdSec'i yükleyin - -Öncelikle, aşağıdaki komutu çalıştırarak CrowdSec deposunu sisteminize eklemeniz gerekir: - -#### Repo ve GPG anahtarını manul ekleme yöntemi - -```bash -echo 'deb https://packages.crowdsec.net/deb stable main' | sudo tee /etc/apt/sources.list.d/crowdsec.list -``` - -Ardından, aşağıdaki komutu çalıştırarak CrowdSec imzalama anahtarını sisteminize eklemeniz gerekir: - -```bash -wget -qO - https://packages.crowdsec.net/crowdsec.gpg.key | sudo apt-key add - -``` - -#### Otomatikleştirilmiş script ile Repo ve GPG anahtarının eklenmesi - -```bash -curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | sudo bash -``` - -|Debian[^3]|Ubuntu[^4]| -|:---:|:---:| -| ![](/images/crowdsec/1.jpg) | ![](/images/crowdsec/1-1.jpg) | - -[^3]: https://www.youtube.com/watch?v=7jwVkWt_4TI (Erişim Tarihi: 11.04.2023) -[^4]: https://www.youtube.com/watch?v=2kW_200N60k (Erişim Tarihi: 11.04.2023) - -Depoyu ve anahtarı ekledikten sonra CrowdSec'i aşağıdaki komutu çalıştırarak kurulumu yapabilirsiniz: - -```bash -sudo apt update && sudo apt install crowdsec -``` - -|Debian[^3]|Ubuntu[^4]| -|:---:|:---:| -| ![](/images/crowdsec/2.jpg) | ![](/images/crowdsec/2-1.jpg) | - -### 2.1.2 CrowdSec'i yapılandırın - -CrowdSec yüklendikten sonra ihtiyaçlarınıza göre yapılandırmanız gerekir. CrowdSec için ana yapılandırma dosyası `/etc/crowdsec/config.yaml` konumunda bulunur. Bu dosyayı nano veya vim gibi bir metin düzenleyici kullanarak düzenleyebilirsiniz. - -Yapılandırma dosyası iyi yorumlanmıştır, bu nedenle her seçeneğin ne yaptığını anlamak kolaydır. CrowdSec tarafından kullanılan Bouncer ve Parserların yanı sıra log kaydı alma, engelleme ve bildirim seçeneklerini özelleştirebilirsiniz. - -### 2.1.3 CrowdSec'i Başlatın - -CrowdSec'i yapılandırdıktan sonra, aşağıdaki komutu çalıştırarak hizmeti başlatabilirsiniz: - -```bash -sudo systemctl start crowdsec -``` - -Aşağıdaki komutu çalıştırarak CrowdSec'in durumunu kontrol edebilirsiniz: - -```bash -sudo systemctl status crowdsec -``` - -CrowdSec düzgün çalışıyorsa hizmetin etkin olduğunu belirten bir mesaj görmelisiniz. - -![Debian(3)](/images/crowdsec/3.jpg) - -### 2.1.4 Bir Linux Bouncer Kurun - -Linux Bouncer, sunucunuzu siber tehditlere karşı korumaya yardımcı olabilecek ek bir güvenlik katmanıdır. Bouncerlar, ağ trafiğini izleyerek ve bilinen kötü amaçlı IP adreslerinden gelen istekleri engelleyerek çalışır. - -CrowdSec, iptables bouncer ve nftables bouncer dahil olmak üzere kurabileceğiniz birkaç bouncer ile birlikte gelir. - -#### Iptables Bouncer yüklemek için aşağıdaki komutu çalıştırın - -```bash -sudo apt install crowdsec-firewall-bouncer -``` - -![Ubuntu(4)](/images/crowdsec/4.jpg) - -#### Nftables Bouncer yüklemek için aşağıdaki komutu çalıştırın - -```bash -sudo apt install crowdsec-nftables-bouncer -``` - -Bir bouncer kurduktan sonra onu CrowdSec ile çalışacak şekilde yapılandırmanız gerekir. bouncer için yapılandırma dosyası `/etc/crowdsec/bouncers.yaml` konumunda bulunur. Bu dosyayı nano veya vim gibi bir metin düzenleyici kullanarak düzenleyebilirsiniz. - -Yapılandırma dosyası iyi yorumlanmıştır, bu nedenle her seçeneğin ne yaptığını anlamak kolaydır. CrowdSec tarafından kullanılan Bouncer ve Parserların yanı sıra günlüğe kaydetme, engelleme ve bildirim seçeneklerini özelleştirebilirsiniz. - -### 2.1.5 Bouncer'ı Başlatın - -bouncer yapılandırdıktan sonra, aşağıdaki komutu çalıştırarak hizmeti başlatabilirsiniz: - -#### Iptables için - -```bash -sudo systemctl start crowdsec-firewall-bouncer -``` - -Aşağıdaki komutu çalıştırarak bouncerların durumunu kontrol edebilirsiniz: - -```bash -sudo systemctl status crowdsec-firewall-bouncer -``` - -#### Nftables için - -```bash -sudo systemctl start crowdsec-nftables-bouncer -``` - -Aşağıdaki komutu çalıştırarak bouncerların durumunu kontrol edebilirsiniz: - -```bash -sudo systemctl status crowdsec-nftables-b -``` - -Aşağıdaki komutu çalıştırarak CrowdSec'in durumunu kontrol edebilirsiniz: - -```bash -sudo systemctl status crowdsec -``` - -CrowdSec düzgün çalışıyorsa hizmetin etkin olduğunu belirten bir mesaj görmelisiniz. - -![Debian(3)](/images/crowdsec/3.jpg) - -### 2.1.6 CrowdSec'i Test Edin - -CrowdSec'in düzgün çalıştığını test etmek için sunucunuza farklı bir IP adresinden birkaç kez giriş yapmayı deneyebilirsiniz. Birkaç başarısız oturum açma denemesinden sonra CrowdSec, başarısız denemelerle ilişkili IP adresini bloke etmelidir. - -Engellenen IP adreslerini aşağıdaki komutu çalıştırarak kontrol edebilirsiniz: - -```bash -sudo cscli alerts list -``` - -Bu komut size CrowdSec tarafından engellenen IP adreslerinin bir listesini gösterecektir. - -### 2.1.7 Kısa Özet - -(TL;DR) [^2] CrowdSec'i Linux sunucunuza yüklemek, sunucunuzu gerçek zamanlı olarak siber tehditlere karşı korumaya yardımcı olabilecek basit bir işlemdir. CrowdSec, yeni ve gelişmekte olan tehditleri algılamak için toplu zekayı kullanarak geleneksel güvenlik çözümlerinden daha yüksek düzeyde koruma sağlar. Bu gönderide belirtilen adımları izleyerek CrowdSec'i Linux sunucunuza yükleyip yapılandırabilir ve dijital varlıklarınızı korumaya başlayabilirsiniz. - -# 3. CrowdSec Nasıl Çalışır? - -CrowdSec, toplu zeka kullanarak siber tehditlere karşı gerçek zamanlı koruma sağlayan, Linux sunucuları için açık kaynaklı bir güvenlik çözümüdür. Bu blog gönderisinde, CrowdSec'in nasıl çalıştığını ve işleyişinde yer alan farklı bileşenleri tartışacağız. - -## 3.1 Zararlı Trafiği Tespit ve İşleme - -CrowdSec, çeşitli kaynaklardan veri toplayarak, ilgili bilgileri çıkarmak için verileri ayrıştırarak ve olası tehditleri belirlemek için senaryolar uygulayarak çalışır. Bir tehdit belirlenirse, IP adresini bloke etmek veya bir bildirim göndermek gibi uygun eylem gerçekleştirilir. - -CrowdSec, potansiyel tehditleri belirleme yeteneğini geliştirmek için toplu zekayı da kullanır. Bir tehdit belirlendiğinde, benzer tehditleri belirleme becerilerini geliştirmek için bilgiler diğer CrowdSec kullanıcılarıyla paylaşılır. - -### 3.1.1 Data Sources - -CrowdSec, olası tehditleri belirlemek için çeşitli kaynaklardan veri toplar. Bu veri kaynakları, sistem günlüklerini, ağ trafiğini ve üçüncü taraf API'leri içerir. Toplanan veriler daha sonra ilgili bilgileri çıkarmak için Parserlar tarafından işlenir. - -### 3.1.2 Parsers - -Parserlar, toplanan verilerden ilgili bilgileri çıkarmak için kullanılır. CrowdSec, sistem günlükleri, ağ trafiği ve üçüncü taraf API'ler için yerleşik Parserlarla birlikte gelir. Ayrıca, diğer kaynaklardan bilgi ayıklamak için özel Parserlar oluşturabilirsiniz. - -### 3.1.3 Scenarios - -Senaryolar, olası tehditleri belirlemeye yönelik kuralları tanımlamak için kullanılır. CrowdSec, kaba kuvvet saldırıları ve bağlantı noktası taraması gibi yaygın tehditler için yerleşik senaryolarla birlikte gelir. Ayrıca, ortamınızla ilgili belirli tehditleri belirlemek için özel senaryolar da oluşturabilirsiniz. - -### 3.1.4 Collections - -Koleksiyonlar, benzer senaryoları birlikte gruplandırmak için kullanılır. Bu, senaryoların yönetimini ve dağıtımını basitleştirmeye yardımcı olur. CrowdSec, SSH ve HTTP gibi yaygın tehdit türleri için yerleşik koleksiyonlarla birlikte gelir. Senaryoları gerektiği gibi gruplandırmak için özel koleksiyonlar da oluşturabilirsiniz. - -### 3.1.5 Kısa Özet - -(TL;DR) [^2] CrowdSec, siber tehditlere karşı gerçek zamanlı koruma sağlayan, Linux sunucuları için güçlü bir açık kaynaklı güvenlik çözümüdür. CrowdSec, çeşitli kaynaklardan veri toplayarak, verileri ayrıştırarak ve senaryolar uygulayarak potansiyel tehditleri belirleyebilir ve uygun önlemleri alabilir. Ek olarak, toplu zekanın kullanılması, CrowdSec'in potansiyel tehditleri belirleme yeteneğini sürekli olarak geliştirmesine olanak tanıyarak onu herhangi bir Linux sunucusu için etkili bir güvenlik çözümü haline getirir. - -## 3.2 Zararlı Trafiği Engelleme Yöntemleri - -CrowdSec, siber tehditlere karşı gerçek zamanlı koruma sağlayan, Linux sunucuları için açık kaynaklı bir güvenlik çözümüdür. CrowdSec'in temel özelliklerinden biri, yasaklama, captcha'lar ve özel kararlar dahil olmak üzere çeşitli yöntemler kullanarak yasal olmayan trafiği önleme yeteneğidir. Bu blog gönderisinde, bu yöntemleri ve sunucunuzun güvenliğini artırmak için nasıl kullanılabileceğini ayrıntılı olarak tartışacağız. - -### 3.2.1 Ban - -![https://tr.wordpress.org/plugins/crowdsec/ (Erişim Tarihi: 11.04.2023)](/images/crowdsec/5-ban.jpg) - -Yasaklama, meşru olmayan trafiği önlemenin en basit yöntemidir. CrowdSec potansiyel bir tehdit belirlediğinde, daha fazla erişimi engellemek için rahatsız edici IP adresini engelleyebilir. Bu, IP adresini her yeni bağlantı kurulduğunda kontrol edilen bir kara listeye ekleyerek yapılır. Yasaklama, tekrarlayan suçluların sunucunuza erişmesini önlemenin etkili bir yoludur, ancak aynı zamanda yanlış pozitiflere yol açabilir ve meşru trafiği engelleyebilir. - -### 3.2.2 Captcha - -![https://tr.wordpress.org/plugins/crowdsec/ (Erişim Tarihi: 11.04.2023)](/images/crowdsec/6-captcha.jpg) - -Captcha, otomatik botların sunucunuza erişmesini engellemek için yaygın olarak kullanılan bir yöntemdir. CrowdSec potansiyel bir tehdit belirlediğinde, kullanıcıya bir captcha sorgulaması sunabilir. Bu zorluk tipik olarak belirli görüntüleri tanımlamayı veya bir dizi karakter girmeyi içerir. Kullanıcı captcha sınamasını geçerse, sunucunuza erişebilir. Captcha, otomatik botların sunucunuza erişmesini önlemenin etkili bir yoludur, ancak gelişmiş botlar tarafından da atlanabilir. - -### 3.2.3 Custom Decision - -CrowdSec, belirli senaryolara göre özel kararlar almanıza da olanak tanır. Örneğin, sürekli olarak sunucunuza erişmeye çalışan bir IP adresi tespit ederseniz, bu IP adresinden gelecek tüm istekleri engellemeye karar verebilirsiniz. Alternatif olarak, kullanıcıyı farklı bir sayfaya yönlendirmeyi veya özel bir mesaj görüntülemeyi seçebilirsiniz. Özel kararlar, CrowdSec'in yanıtını belirli senaryolara uyarlamanıza olanak tanıyarak sunucunuzun güvenliği üzerinde daha fazla kontrol sahibi olmanızı sağlar. - -### 3.2.3 Kısa Özet - -(TL;DR) [^2] CrowdSec, siber tehditlere karşı gerçek zamanlı koruma sağlayan Linux sunucuları için güçlü bir güvenlik çözümüdür. CrowdSec, yasaklama, captcha'lar ve özel kararlar gibi yöntemleri kullanarak meşru olmayan trafiği önleyebilir ve sunucunuzun güvenliğini artırabilir. İster küçük bir web sitesi ister büyük bir kurumsal uygulama çalıştırıyor olun, CrowdSec sunucunuzu siber tehditlere karşı korumanıza ve kullanıcılarınızın sitenize güvenli bir şekilde erişmesini sağlamanıza yardımcı olabilir. - -# 4. Crowdsec İle Tech Demo - -{{< youtube kG68PgwOOeU >}} -> -> -> Crowdsec Youtube Kanalı (Erişim Tarihi: 11.04.2023) - -Günümüzün dijital çağında, Dağıtılmış Hizmet Reddi (DDoS) saldırıları, işletmeler ve kuruluşlar için ortak bir tehdit haline geldi. Bu saldırılar, bir web sitesini veya uygulamayı trafikle doldurmak, trafiği bunaltmak ve meşru kullanıcılar için kullanılamaz hale getirmek için tasarlanmıştır. Önde gelen bir güvenlik çözümleri sağlayıcısı olan CrowdSec, yakın tarihli bir [blog gönderisinde (Erişim Tarihi: 11.04.2023)](https://www.crowdsec.net/blog/how-to-beat-application-ddos), uygulama DDoS saldırılarını yenmek için bazı etkili stratejiler paylaştı. - -Blog gönderisi, kuruluşların karşılaşabileceği farklı uygulama DDoS saldırı türlerini açıklayarak başlıyor. Bunlar, HTTP/S Flood, Slow R/W Atağı (Slowloris) ve Application Layer Atak saldırılarını içerir. Her saldırı türü farklı bir yürütme yöntemine sahip olsa da, hepsi bir uygulamayı aşırı yükleyerek kullanıcılar tarafından kullanılamaz hale getirmeyi amaçlar. - -Gönderi daha sonra uygulama DDoS saldırılarını yenmek için bazı etkili teknikleri açıklamaya devam ediyor. En önemli stratejilerden biri, kapsamlı bir DDoS koruma yazılımına sahip olmaktır. Bu, diğer önlemlerin yanı sıra güvenlik duvarlarının, izinsiz giriş tespit sistemlerinin (IDS), izinsiz giriş engelleme sisstemlerinin (IPS) ve yük dengeleyicilerin (Load Balancing) kurulmasını içerir. - -Diğer bir etkili yaklaşım, İçerik Dağıtım Ağlarını (CDN'ler) kullanmaktır. CDN'ler, trafiği birden çok sunucu arasında dağıtmaya yardımcı olur ve bu da bir saldırının etkisini azaltmaya yardımcı olabilir. Ek olarak, CDN'ler, meşru kullanıcılar için performansını iyileştirerek bir uygulamanın gecikmesini azaltmaya yardımcı olabilir. - -Gönderi ayrıca hız sınırlayıcı tekniklerin uygulanmasını önerir. Bu, belirli bir zaman çerçevesi içinde bir uygulamaya gönderilebilecek trafik miktarına ilişkin sınırlar belirlemeyi içerir. Rate Limiting (Hız sınırlama), bir uygulamaya gönderilebilecek trafik miktarını sınırlayarak uygulama DDoS saldırılarını önlemeye yardımcı olabilir. - -Son olarak gönderi, tüm yazılımları güncel tutmanızı önerir. Buna işletim sistemleri, web sunucuları ve uygulamalar dahildir. Yazılımı güncel tutmak, bilinen tüm güvenlik açıklarının yamalanmasını sağlamaya yardımcı olarak saldırı riskini azaltır. - -Sonuç olarak, uygulama DDoS saldırıları, işletmeler ve kuruluşlar için önemli bir tehdit olabilir. Ancak doğru stratejiler uygulandığında bu saldırıları yenmek ve uygulamaları ve web sitelerini çevrimiçi tutmak mümkündür. Kuruluşlar, kapsamlı bir DDoS koruma planı uygulayarak, CDN'leri kullanarak, hız sınırlayıcı teknikler uygulayarak ve yazılımları güncel tutarak, bir uygulama DDoS saldırısı riskini önemli ölçüde azaltabilir. - -## 4.1 Beta Sürümü ve Geleceği Hakkında - -![Crowdsec Beta Duyurusu (Erişim Tarihi: 11.04.2023)](/images/crowdsec/crowdsec-beta.png) - -Crowdsec yazılımı yakın zaman önce v1.5 Beta sürümünü[^5] kısıtlı kullanıma açtı. Kısıtlı test için yapmış olduğum başvuruyu kabul etmeleri sebebiyle kendilerine öncelikle teşekkür ediyorum. Mevcut trendlere ve siber güvenlik çözümlerine yönelik artan talebe dayanarak, Crowdsec yazılımının önümüzdeki yıllarda büyümeye ve popülerlik kazanmaya devam edeceğini tahmin ediyorum. Yazılımın, topluluk zekası ve makine öğrenimi algoritmalarını kullanarak tehdit algılama ve hafifletmeye yönelik benzersiz yaklaşımı, sektörde potansiyel olarak devrim yaratabilecek umut verici bir yeniliktir. - -[^5]: https://www.crowdsec.net/blog/crowdsec-v1-5-beta - -Ayrıca, açık kaynak topluluğundan gelen güçlü destek, Crowdsec'in başarısının arkasındaki itici güç olmuştur. Yazılımın açık kaynak olması ve herkesin kullanması ve katkıda bulunması için ücretsiz olarak erişilebilir olması, yazılımı iyileştirmek ve geliştirmek için sürekli çalışan (ve Beta sürümünde olacağı gibi feedback veren) büyük ve özel bir kullanıcı ve geliştirici topluluğunun gelişmesine yardımcı olmuştur. - -Daha fazla insan Crowdsec'in yeteneklerinin farkına vardıkça ve bir açık kaynak projesine katkıda bulunmanın faydalarını gördükçe, bu topluluk desteğinin büyümeye ve güçlenmeye devam etmesini bekliyorum. Topluluğun geri bildirimleri ve katkıları, Crowdsec'in siber güvenlik sektörünün ön saflarında kalmasını sağlayarak yeni özelliklerin ve iyileştirmelerin geliştirilmesine yardımcı olacaktır. Bu nedenle bir sonraki blog yazımda Crowdsec'in Beta sürümünü inceleyip deneyimlerimi paylaşacağım. +--- +title: "Crowdsec IPS/IDS Yazılımı" +date: 2023-04-11 +tags: ["linux", "bot", "botnet", "dos", "ddos", "crowdsec", "ıps", "ids", "parser", "scenario", "data source", "ban", "captcha","ip", "asn", "subnet", "ip block"] +author: "Wise" +draft: false +--- +# 1. Crowdsec IPS/IDS Yazılımı Tanıtımı + +CrowdSec, siber tehditlere karşı gerçek zamanlı koruma sağlamak için kolektif bir zeka yaklaşımı kullanan Linux sunucuları için açık kaynaklı bir güvenlik çözümüdür. Bu blog gönderisinde, CrowdSec'in (v.1.4.6)[^1] özelliklerini, Linux sunucularınızı korumak için neden harika bir seçim olduğunun nedenlerini ve CrowdSec ile diğer IPS/IDS yazılımları arasındaki farkları ve benzerlikleri keşfedeceğiz. + +[^1]: https://github.com/crowdsecurity/crowdsec/releases/tag/v1.4.6 + +## 1.1 CrowdSec'in Özellikleri + +CrowdSec, onu Linux sunucuları için güçlü ve etkili bir güvenlik çözümü yapan çeşitli özellikler sunar. Temel özelliklerinden bazıları şunlardır: + +### 1.1.1 Gerçek zamanlı tehdit tespiti + +* CrowdSec, tehditleri gerçek zamanlı olarak tespit etmek için makine öğrenimi algoritmalarını kullanır ve saldırıların gerçekleşmesini önler. + +### 1.1.2 Otomatik engelleme + +* Bir tehdit algılandığında CrowdSec, saldırıyla ilişkili IP adresini otomatik olarak engelleyerek anında koruma sağlar. + +### 1.1.3 Kolektif zeka + +* CrowdSec, yeni ve gelişmekte olan tehditleri algılamak için diğer CrowdSec kullanıcıları da dahil olmak üzere birden çok kaynaktan gelen verilerden yararlanır. + +### 1.1.4 Kolay entegrasyon + +* CrowdSec, kapsamlı bir güvenlik çözümü sağlamak için güvenlik duvarları ve SIEM'ler gibi diğer güvenlik çözümleriyle kolayca entegre edilebilir. + +### 1.1.5 Özelleştirilebilir kurallar + +* CrowdSec, kullanıcıların güvenlik politikalarının kendi özel gereksinimleriyle uyumlu olmasını sağlayarak kendi kurallarını oluşturmasına ve özelleştirmesine olanak tanır. + +## 1.2 Neden CrowdSec'i Seçmelisiniz? + +CrowdSec'in Linux sunucularınızın güvenliğini sağlamak için mükemmel bir seçim olmasının birkaç nedeni vardır. Bu nedenlerden bazıları şunlardır: + +### 1.2.1 Açık kaynak + +* CrowdSec açık kaynaklı bir çözümdür, yani kullanımı ücretsizdir ve özel ihtiyaçlarınızı karşılayacak şekilde kolayca özelleştirilebilir. + +### 1.2.2 Toplu zeka + +* CrowdSec, yeni ve gelişmekte olan tehditleri tespit etmek için toplu zekanın gücünden yararlanarak geleneksel güvenlik çözümlerinden daha yüksek düzeyde koruma sağlar. + +### 1.2.3 Kolay entegrasyon + +* CrowdSec, diğer güvenlik çözümleriyle kolayca entegre edilebilir ve bu da onu her kuruluş için esnek ve uyarlanabilir bir çözüm haline getirir. + +### 1.2.4 Özelleştirilebilir kurallar + +* CrowdSec, kullanıcıların güvenlik politikalarının kendi özel gereksinimleriyle uyumlu olmasını sağlayarak kendi kurallarını oluşturmasına ve özelleştirmesine olanak tanır. + +## 1.3 CrowdSec ve Cloudflare Arasındaki Fark ve Benzerlikler + +CrowdSec ve Cloudflare güvenlik çözümleri olmakla birlikte, ikisi arasında bazı temel farklılıklar vardır. Örneğin: + +### 1.3.1 Farkları + +* CrowdSec açık kaynaklı bir çözümken Cloudflare ticari bir çözümdür. + +* CrowdSec, yeni ve gelişmekte olan tehditleri algılamak için toplu zekayı kullanırken Cloudflare, makine öğrenimi ve imza tabanlı algılamanın bir kombinasyonunu kullanır. + +* CrowdSec, Linux sunucularını korumaya odaklanırken, Cloudflare çok çeşitli platformlar için güvenlik çözümleri sunar. + +### 1.3.2 Benzerlikleri + +Bu farklılıklara rağmen, hem CrowdSec hem de Cloudflare bazı benzerlikleri paylaşır. Örneğin: + +* Her iki çözüm de tehditleri gerçek zamanlı olarak algılamak için makine öğrenimi algoritmalarını kullanır. + +* Her iki çözüm de kötü amaçlı IP adreslerinin otomatik olarak engellenmesini sağlar. + +* Her iki çözüm de diğer güvenlik çözümleriyle kolayca entegre edilebilir ve kapsamlı bir güvenlik çözümü sunar. + +## 1.4 Kısa Özet + +(TL;DR) [^2] CrowdSec, Linux sunucuları için gerçek zamanlı tehdit algılama, otomatik engelleme ve toplu zeka sağlayan güçlü ve etkili bir güvenlik çözümüdür. Açık kaynak yapısı, kolay entegrasyonu ve özelleştirilebilir kuralları, onu Linux sunucularının güvenliğini sağlamak isteyen tüm kuruluşlar için mükemmel bir seçim haline getirir. CrowdSec ve Cloudflare arasında bazı farklılıklar olsa da, her iki çözüm de bazı benzerliklere sahiptir ve dijital varlıklarını güvence altına almak isteyen kuruluşlar için mükemmel seçeneklerdir. + +[^2]: TL;DR: `Too long; Didn't read` veya `Çok uzundu; okumadım` özet geç anlamında + +# 2. Crowdsec Linux Nasıl Kurulur + +CrowdSec, siber tehditlere karşı gerçek zamanlı koruma sağlamak için toplu zeka kullanan Linux sunucuları için açık kaynaklı bir güvenlik çözümüdür. Blog yazısının bu kısmında CrowdSec'i Linux sunucunuza kurma adımlarının yanı sıra sunucunuzun güvenliğini daha da artırmak için bir Linux bouncer'ı nasıl kuracağınız konusunda size yol göstereceğiz. + +## 2.1 Adım Adım Kılavuz + +Başlamadan önce, kurulum işleminin Linux dağıtımınıza bağlı olarak değişebileceğini lütfen unutmayın. Aşağıdaki adımlar Ubuntu 20.04'ü temel alır, ancak diğer dağıtımlar için talimatları CrowdSec dokümantasyon sayfasında bulabilirsiniz. + +### 2.1.1 CrowdSec'i yükleyin + +Öncelikle, aşağıdaki komutu çalıştırarak CrowdSec deposunu sisteminize eklemeniz gerekir: + +#### Repo ve GPG anahtarını manul ekleme yöntemi + +```bash +echo 'deb https://packages.crowdsec.net/deb stable main' | sudo tee /etc/apt/sources.list.d/crowdsec.list +``` + +Ardından, aşağıdaki komutu çalıştırarak CrowdSec imzalama anahtarını sisteminize eklemeniz gerekir: + +```bash +wget -qO - https://packages.crowdsec.net/crowdsec.gpg.key | sudo apt-key add - +``` + +#### Otomatikleştirilmiş script ile Repo ve GPG anahtarının eklenmesi + +```bash +curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | sudo bash +``` + +|Debian[^3]|Ubuntu[^4]| +|:---:|:---:| +| ![](/images/crowdsec/1.jpg) | ![](/images/crowdsec/1-1.jpg) | + +[^3]: https://www.youtube.com/watch?v=7jwVkWt_4TI (Erişim Tarihi: 11.04.2023) +[^4]: https://www.youtube.com/watch?v=2kW_200N60k (Erişim Tarihi: 11.04.2023) + +Depoyu ve anahtarı ekledikten sonra CrowdSec'i aşağıdaki komutu çalıştırarak kurulumu yapabilirsiniz: + +```bash +sudo apt update && sudo apt install crowdsec +``` + +|Debian[^3]|Ubuntu[^4]| +|:---:|:---:| +| ![](/images/crowdsec/2.jpg) | ![](/images/crowdsec/2-1.jpg) | + +### 2.1.2 CrowdSec'i yapılandırın + +CrowdSec yüklendikten sonra ihtiyaçlarınıza göre yapılandırmanız gerekir. CrowdSec için ana yapılandırma dosyası `/etc/crowdsec/config.yaml` konumunda bulunur. Bu dosyayı nano veya vim gibi bir metin düzenleyici kullanarak düzenleyebilirsiniz. + +Yapılandırma dosyası iyi yorumlanmıştır, bu nedenle her seçeneğin ne yaptığını anlamak kolaydır. CrowdSec tarafından kullanılan Bouncer ve Parserların yanı sıra log kaydı alma, engelleme ve bildirim seçeneklerini özelleştirebilirsiniz. + +### 2.1.3 CrowdSec'i Başlatın + +CrowdSec'i yapılandırdıktan sonra, aşağıdaki komutu çalıştırarak hizmeti başlatabilirsiniz: + +```bash +sudo systemctl start crowdsec +``` + +Aşağıdaki komutu çalıştırarak CrowdSec'in durumunu kontrol edebilirsiniz: + +```bash +sudo systemctl status crowdsec +``` + +CrowdSec düzgün çalışıyorsa hizmetin etkin olduğunu belirten bir mesaj görmelisiniz. + +![Debian(3)](/images/crowdsec/3.jpg) + +### 2.1.4 Bir Linux Bouncer Kurun + +Linux Bouncer, sunucunuzu siber tehditlere karşı korumaya yardımcı olabilecek ek bir güvenlik katmanıdır. Bouncerlar, ağ trafiğini izleyerek ve bilinen kötü amaçlı IP adreslerinden gelen istekleri engelleyerek çalışır. + +CrowdSec, iptables bouncer ve nftables bouncer dahil olmak üzere kurabileceğiniz birkaç bouncer ile birlikte gelir. + +#### Iptables Bouncer yüklemek için aşağıdaki komutu çalıştırın + +```bash +sudo apt install crowdsec-firewall-bouncer +``` + +![Ubuntu(4)](/images/crowdsec/4.jpg) + +#### Nftables Bouncer yüklemek için aşağıdaki komutu çalıştırın + +```bash +sudo apt install crowdsec-nftables-bouncer +``` + +Bir bouncer kurduktan sonra onu CrowdSec ile çalışacak şekilde yapılandırmanız gerekir. bouncer için yapılandırma dosyası `/etc/crowdsec/bouncers.yaml` konumunda bulunur. Bu dosyayı nano veya vim gibi bir metin düzenleyici kullanarak düzenleyebilirsiniz. + +Yapılandırma dosyası iyi yorumlanmıştır, bu nedenle her seçeneğin ne yaptığını anlamak kolaydır. CrowdSec tarafından kullanılan Bouncer ve Parserların yanı sıra günlüğe kaydetme, engelleme ve bildirim seçeneklerini özelleştirebilirsiniz. + +### 2.1.5 Bouncer'ı Başlatın + +bouncer yapılandırdıktan sonra, aşağıdaki komutu çalıştırarak hizmeti başlatabilirsiniz: + +#### Iptables için + +```bash +sudo systemctl start crowdsec-firewall-bouncer +``` + +Aşağıdaki komutu çalıştırarak bouncerların durumunu kontrol edebilirsiniz: + +```bash +sudo systemctl status crowdsec-firewall-bouncer +``` + +#### Nftables için + +```bash +sudo systemctl start crowdsec-nftables-bouncer +``` + +Aşağıdaki komutu çalıştırarak bouncerların durumunu kontrol edebilirsiniz: + +```bash +sudo systemctl status crowdsec-nftables-b +``` + +Aşağıdaki komutu çalıştırarak CrowdSec'in durumunu kontrol edebilirsiniz: + +```bash +sudo systemctl status crowdsec +``` + +CrowdSec düzgün çalışıyorsa hizmetin etkin olduğunu belirten bir mesaj görmelisiniz. + +![Debian(3)](/images/crowdsec/3.jpg) + +### 2.1.6 CrowdSec'i Test Edin + +CrowdSec'in düzgün çalıştığını test etmek için sunucunuza farklı bir IP adresinden birkaç kez giriş yapmayı deneyebilirsiniz. Birkaç başarısız oturum açma denemesinden sonra CrowdSec, başarısız denemelerle ilişkili IP adresini bloke etmelidir. + +Engellenen IP adreslerini aşağıdaki komutu çalıştırarak kontrol edebilirsiniz: + +```bash +sudo cscli alerts list +``` + +Bu komut size CrowdSec tarafından engellenen IP adreslerinin bir listesini gösterecektir. + +### 2.1.7 Kısa Özet + +(TL;DR) [^2] CrowdSec'i Linux sunucunuza yüklemek, sunucunuzu gerçek zamanlı olarak siber tehditlere karşı korumaya yardımcı olabilecek basit bir işlemdir. CrowdSec, yeni ve gelişmekte olan tehditleri algılamak için toplu zekayı kullanarak geleneksel güvenlik çözümlerinden daha yüksek düzeyde koruma sağlar. Bu gönderide belirtilen adımları izleyerek CrowdSec'i Linux sunucunuza yükleyip yapılandırabilir ve dijital varlıklarınızı korumaya başlayabilirsiniz. + +# 3. CrowdSec Nasıl Çalışır? + +CrowdSec, toplu zeka kullanarak siber tehditlere karşı gerçek zamanlı koruma sağlayan, Linux sunucuları için açık kaynaklı bir güvenlik çözümüdür. Bu blog gönderisinde, CrowdSec'in nasıl çalıştığını ve işleyişinde yer alan farklı bileşenleri tartışacağız. + +## 3.1 Zararlı Trafiği Tespit ve İşleme + +CrowdSec, çeşitli kaynaklardan veri toplayarak, ilgili bilgileri çıkarmak için verileri ayrıştırarak ve olası tehditleri belirlemek için senaryolar uygulayarak çalışır. Bir tehdit belirlenirse, IP adresini bloke etmek veya bir bildirim göndermek gibi uygun eylem gerçekleştirilir. + +CrowdSec, potansiyel tehditleri belirleme yeteneğini geliştirmek için toplu zekayı da kullanır. Bir tehdit belirlendiğinde, benzer tehditleri belirleme becerilerini geliştirmek için bilgiler diğer CrowdSec kullanıcılarıyla paylaşılır. + +### 3.1.1 Data Sources + +CrowdSec, olası tehditleri belirlemek için çeşitli kaynaklardan veri toplar. Bu veri kaynakları, sistem günlüklerini, ağ trafiğini ve üçüncü taraf API'leri içerir. Toplanan veriler daha sonra ilgili bilgileri çıkarmak için Parserlar tarafından işlenir. + +### 3.1.2 Parsers + +Parserlar, toplanan verilerden ilgili bilgileri çıkarmak için kullanılır. CrowdSec, sistem günlükleri, ağ trafiği ve üçüncü taraf API'ler için yerleşik Parserlarla birlikte gelir. Ayrıca, diğer kaynaklardan bilgi ayıklamak için özel Parserlar oluşturabilirsiniz. + +### 3.1.3 Scenarios + +Senaryolar, olası tehditleri belirlemeye yönelik kuralları tanımlamak için kullanılır. CrowdSec, kaba kuvvet saldırıları ve bağlantı noktası taraması gibi yaygın tehditler için yerleşik senaryolarla birlikte gelir. Ayrıca, ortamınızla ilgili belirli tehditleri belirlemek için özel senaryolar da oluşturabilirsiniz. + +### 3.1.4 Collections + +Koleksiyonlar, benzer senaryoları birlikte gruplandırmak için kullanılır. Bu, senaryoların yönetimini ve dağıtımını basitleştirmeye yardımcı olur. CrowdSec, SSH ve HTTP gibi yaygın tehdit türleri için yerleşik koleksiyonlarla birlikte gelir. Senaryoları gerektiği gibi gruplandırmak için özel koleksiyonlar da oluşturabilirsiniz. + +### 3.1.5 Kısa Özet + +(TL;DR) [^2] CrowdSec, siber tehditlere karşı gerçek zamanlı koruma sağlayan, Linux sunucuları için güçlü bir açık kaynaklı güvenlik çözümüdür. CrowdSec, çeşitli kaynaklardan veri toplayarak, verileri ayrıştırarak ve senaryolar uygulayarak potansiyel tehditleri belirleyebilir ve uygun önlemleri alabilir. Ek olarak, toplu zekanın kullanılması, CrowdSec'in potansiyel tehditleri belirleme yeteneğini sürekli olarak geliştirmesine olanak tanıyarak onu herhangi bir Linux sunucusu için etkili bir güvenlik çözümü haline getirir. + +## 3.2 Zararlı Trafiği Engelleme Yöntemleri + +CrowdSec, siber tehditlere karşı gerçek zamanlı koruma sağlayan, Linux sunucuları için açık kaynaklı bir güvenlik çözümüdür. CrowdSec'in temel özelliklerinden biri, yasaklama, captcha'lar ve özel kararlar dahil olmak üzere çeşitli yöntemler kullanarak yasal olmayan trafiği önleme yeteneğidir. Bu blog gönderisinde, bu yöntemleri ve sunucunuzun güvenliğini artırmak için nasıl kullanılabileceğini ayrıntılı olarak tartışacağız. + +### 3.2.1 Ban + +![https://tr.wordpress.org/plugins/crowdsec/ (Erişim Tarihi: 11.04.2023)](/images/crowdsec/5-ban.jpg) + +Yasaklama, meşru olmayan trafiği önlemenin en basit yöntemidir. CrowdSec potansiyel bir tehdit belirlediğinde, daha fazla erişimi engellemek için rahatsız edici IP adresini engelleyebilir. Bu, IP adresini her yeni bağlantı kurulduğunda kontrol edilen bir kara listeye ekleyerek yapılır. Yasaklama, tekrarlayan suçluların sunucunuza erişmesini önlemenin etkili bir yoludur, ancak aynı zamanda yanlış pozitiflere yol açabilir ve meşru trafiği engelleyebilir. + +### 3.2.2 Captcha + +![https://tr.wordpress.org/plugins/crowdsec/ (Erişim Tarihi: 11.04.2023)](/images/crowdsec/6-captcha.jpg) + +Captcha, otomatik botların sunucunuza erişmesini engellemek için yaygın olarak kullanılan bir yöntemdir. CrowdSec potansiyel bir tehdit belirlediğinde, kullanıcıya bir captcha sorgulaması sunabilir. Bu zorluk tipik olarak belirli görüntüleri tanımlamayı veya bir dizi karakter girmeyi içerir. Kullanıcı captcha sınamasını geçerse, sunucunuza erişebilir. Captcha, otomatik botların sunucunuza erişmesini önlemenin etkili bir yoludur, ancak gelişmiş botlar tarafından da atlanabilir. + +### 3.2.3 Custom Decision + +CrowdSec, belirli senaryolara göre özel kararlar almanıza da olanak tanır. Örneğin, sürekli olarak sunucunuza erişmeye çalışan bir IP adresi tespit ederseniz, bu IP adresinden gelecek tüm istekleri engellemeye karar verebilirsiniz. Alternatif olarak, kullanıcıyı farklı bir sayfaya yönlendirmeyi veya özel bir mesaj görüntülemeyi seçebilirsiniz. Özel kararlar, CrowdSec'in yanıtını belirli senaryolara uyarlamanıza olanak tanıyarak sunucunuzun güvenliği üzerinde daha fazla kontrol sahibi olmanızı sağlar. + +### 3.2.3 Kısa Özet + +(TL;DR) [^2] CrowdSec, siber tehditlere karşı gerçek zamanlı koruma sağlayan Linux sunucuları için güçlü bir güvenlik çözümüdür. CrowdSec, yasaklama, captcha'lar ve özel kararlar gibi yöntemleri kullanarak meşru olmayan trafiği önleyebilir ve sunucunuzun güvenliğini artırabilir. İster küçük bir web sitesi ister büyük bir kurumsal uygulama çalıştırıyor olun, CrowdSec sunucunuzu siber tehditlere karşı korumanıza ve kullanıcılarınızın sitenize güvenli bir şekilde erişmesini sağlamanıza yardımcı olabilir. + +# 4. Crowdsec İle Tech Demo + +{{< youtube kG68PgwOOeU >}} +> +> +> Crowdsec Youtube Kanalı (Erişim Tarihi: 11.04.2023) + +Günümüzün dijital çağında, Dağıtılmış Hizmet Reddi (DDoS) saldırıları, işletmeler ve kuruluşlar için ortak bir tehdit haline geldi. Bu saldırılar, bir web sitesini veya uygulamayı trafikle doldurmak, trafiği bunaltmak ve meşru kullanıcılar için kullanılamaz hale getirmek için tasarlanmıştır. Önde gelen bir güvenlik çözümleri sağlayıcısı olan CrowdSec, yakın tarihli bir [blog gönderisinde (Erişim Tarihi: 11.04.2023)](https://www.crowdsec.net/blog/how-to-beat-application-ddos), uygulama DDoS saldırılarını yenmek için bazı etkili stratejiler paylaştı. + +Blog gönderisi, kuruluşların karşılaşabileceği farklı uygulama DDoS saldırı türlerini açıklayarak başlıyor. Bunlar, HTTP/S Flood, Slow R/W Atağı (Slowloris) ve Application Layer Atak saldırılarını içerir. Her saldırı türü farklı bir yürütme yöntemine sahip olsa da, hepsi bir uygulamayı aşırı yükleyerek kullanıcılar tarafından kullanılamaz hale getirmeyi amaçlar. + +Gönderi daha sonra uygulama DDoS saldırılarını yenmek için bazı etkili teknikleri açıklamaya devam ediyor. En önemli stratejilerden biri, kapsamlı bir DDoS koruma yazılımına sahip olmaktır. Bu, diğer önlemlerin yanı sıra güvenlik duvarlarının, izinsiz giriş tespit sistemlerinin (IDS), izinsiz giriş engelleme sisstemlerinin (IPS) ve yük dengeleyicilerin (Load Balancing) kurulmasını içerir. + +Diğer bir etkili yaklaşım, İçerik Dağıtım Ağlarını (CDN'ler) kullanmaktır. CDN'ler, trafiği birden çok sunucu arasında dağıtmaya yardımcı olur ve bu da bir saldırının etkisini azaltmaya yardımcı olabilir. Ek olarak, CDN'ler, meşru kullanıcılar için performansını iyileştirerek bir uygulamanın gecikmesini azaltmaya yardımcı olabilir. + +Gönderi ayrıca hız sınırlayıcı tekniklerin uygulanmasını önerir. Bu, belirli bir zaman çerçevesi içinde bir uygulamaya gönderilebilecek trafik miktarına ilişkin sınırlar belirlemeyi içerir. Rate Limiting (Hız sınırlama), bir uygulamaya gönderilebilecek trafik miktarını sınırlayarak uygulama DDoS saldırılarını önlemeye yardımcı olabilir. + +Son olarak gönderi, tüm yazılımları güncel tutmanızı önerir. Buna işletim sistemleri, web sunucuları ve uygulamalar dahildir. Yazılımı güncel tutmak, bilinen tüm güvenlik açıklarının yamalanmasını sağlamaya yardımcı olarak saldırı riskini azaltır. + +Sonuç olarak, uygulama DDoS saldırıları, işletmeler ve kuruluşlar için önemli bir tehdit olabilir. Ancak doğru stratejiler uygulandığında bu saldırıları yenmek ve uygulamaları ve web sitelerini çevrimiçi tutmak mümkündür. Kuruluşlar, kapsamlı bir DDoS koruma planı uygulayarak, CDN'leri kullanarak, hız sınırlayıcı teknikler uygulayarak ve yazılımları güncel tutarak, bir uygulama DDoS saldırısı riskini önemli ölçüde azaltabilir. + +## 4.1 Beta Sürümü ve Geleceği Hakkında + +![Crowdsec Beta Duyurusu (Erişim Tarihi: 11.04.2023)](/images/crowdsec/crowdsec-beta.png) + +Crowdsec yazılımı yakın zaman önce v1.5 Beta sürümünü[^5] kısıtlı kullanıma açtı. Kısıtlı test için yapmış olduğum başvuruyu kabul etmeleri sebebiyle kendilerine öncelikle teşekkür ediyorum. Mevcut trendlere ve siber güvenlik çözümlerine yönelik artan talebe dayanarak, Crowdsec yazılımının önümüzdeki yıllarda büyümeye ve popülerlik kazanmaya devam edeceğini tahmin ediyorum. Yazılımın, topluluk zekası ve makine öğrenimi algoritmalarını kullanarak tehdit algılama ve hafifletmeye yönelik benzersiz yaklaşımı, sektörde potansiyel olarak devrim yaratabilecek umut verici bir yeniliktir. + +[^5]: https://www.crowdsec.net/blog/crowdsec-v1-5-beta + +Ayrıca, açık kaynak topluluğundan gelen güçlü destek, Crowdsec'in başarısının arkasındaki itici güç olmuştur. Yazılımın açık kaynak olması ve herkesin kullanması ve katkıda bulunması için ücretsiz olarak erişilebilir olması, yazılımı iyileştirmek ve geliştirmek için sürekli çalışan (ve Beta sürümünde olacağı gibi feedback veren) büyük ve özel bir kullanıcı ve geliştirici topluluğunun gelişmesine yardımcı olmuştur. + +Daha fazla insan Crowdsec'in yeteneklerinin farkına vardıkça ve bir açık kaynak projesine katkıda bulunmanın faydalarını gördükçe, bu topluluk desteğinin büyümeye ve güçlenmeye devam etmesini bekliyorum. Topluluğun geri bildirimleri ve katkıları, Crowdsec'in siber güvenlik sektörünün ön saflarında kalmasını sağlayarak yeni özelliklerin ve iyileştirmelerin geliştirilmesine yardımcı olacaktır. Bu nedenle bir sonraki blog yazımda Crowdsec'in Beta sürümünü inceleyip deneyimlerimi paylaşacağım. diff --git a/content/post/ecc-ssl-sertifikasi.de.md b/content/post/ecc-ssl-sertifikasi.de.md index eebdfdc6..b45ef6e6 100644 --- a/content/post/ecc-ssl-sertifikasi.de.md +++ b/content/post/ecc-ssl-sertifikasi.de.md @@ -1,220 +1,220 @@ ---- -title: "Generieren eines ECC-SSL-Zertifikats auf einem Linux-Server" -date: 2022-03-20 -tags: ["linux", "ssl", "sicherheit", "ecc", "elliptische kurve"] -author: "Wise" -draft: false ---- -# Einführung und Zusammenfassung - -Heute lernen wir, wie man SSL-Zertifikate generiert, um sicherzustellen, dass der Datenverkehr zwischen einer von Ihnen verwalteten Website oder einem Anwendungsserver und Ihren Besuchern vertraulich / zuverlässig und überprüfbar ist. In meinen vorherigen Artikeln habe ich erklärt, wie und mit welcher Konfiguration Sie das von Ihnen erstellte Zertifikat bereitstellen würden. In diesem Artikel zeige ich Ihnen, wie Sie die Gleichung „weniger Brot, mehr Frikadellen“ aufstellen, also ein schnelleres und sichereres SSL-Zertifikat erstellen. Wenn Sie mit dem ACME-Protokoll von Let’s Encrypt vertraut sind (zum Zeitpunkt des Schreibens), ist es normalerweise möglich, ein 1024-4098 (wenn Sie sich zu sehr anstrengen, vielleicht 8196) Bit-Zertifikat mit einer asymmetrischen RSA-Schlüsselstruktur zu generieren und es für zu verwenden 90 Tage relativ. Das Generieren eines so großen Schlüssels, dessen Verwendung während des TLS-Handshakes nach der Generierung und die Kompatibilität mit den von den Besuchern verwendeten Geräten verursachen jedoch in den meisten Szenarien Probleme. Wenn beispielsweise 4096 Bit anstelle von 2048 Bit verwendet werden, bin ich bei einigen meiner Versuche mit 0,4-0,8 Sekunden längeren Handshake-Zeiten konfrontiert. Als ob es in Ordnung wäre, dass der Handshake so lange dauert, wird der Server dadurch zusätzlich belastet. Aber wenn Sie ein 384-Bit-ECC-Zertifikat anstelle von 4096-Bit-RSA generieren, erhalten Sie ein viel schnelleres Zertifikat und gleichzeitig eine Sicherheit, die 7680-Bit-RSA entspricht (wenn es diese Größe hätte). - -Nun, Sie haben es gut erklärt, aber wo ist der Sinn dieser Arbeit, scheine ich Sie sagen zu hören. Ich werde Sie verärgern, aber dieses Geschäft hat keinen Sinn. Der Grund, warum dies nicht der Fall ist, ist in der Hintergrundmathematik verborgen. Ich werde kurz auf die kleinen Unterschiede in der Herstellung und Verwendung beider Zertifikate eingehen, erklären, wie und warum sie große Unterschiede verursachen, und im letzten Teil werde ich über etwas sprechen, das nicht als Bonus im Titel steht. (Für den Bonus musst du bis zum Ende lesen :D) - -![https://www.globalsign.com/en/blog/elliptic-curve-cryptography (Datum: 08.04.2023)](/images/ecc-ssl/key-size-comparison.jpg) - -## Produktionsprozess des ECC-Zertifikats - -Zuerst müssen wir (wie immer) die neuesten Updates über die Konsole mit dem Paketmanager der Linux-Version installieren, in der wir uns befinden. - -```bash -Ubuntu: sudo apt update && sudo apt upgrade -y - -Fedora: sudo yum update -y - -Arch Linux: sudo pacman -Syyu -``` - -Nachdem die Updates installiert sind, beginnen wir mit der Konfiguration des nginx-Dienstes (das ist der Dienst, der es Ihnen ermöglicht, externe HTTP/HTTPS-Verbindungen zu empfangen) auf Ihrem Server (in meinem Fall Ubuntu). Zunächst einmal sollte angemerkt werden, dass es sich aufgrund der Verwirrung bei Apache-, Nginx- und Litespeed-Diensten um unterschiedliche Dienste handelt, die die gleiche Aufgabe erfüllen. Ich habe mich für NGINX entschieden, weil es einfacher zu verwalten ist und mehr Community-Unterstützung bietet. - -## Lassen Sie uns den privaten Schlüssel generieren - -Zuerst generieren wir den privaten Schlüssel mit OpenSSL. Der OpenSSL-Befehl, den wir verwenden werden, ist „ecparam“ (EC-Parametermanipulation) und um die Konfigurationsparameter an diesen Befehl zu übergeben: - -```bash -openssl ecparam -genkey -name secp384r1 -out privkey.pem -``` - -* Die Option `-genkey` weist OpenSSL an, einen EC-Schlüssel zu generieren. -* Der Parameter `-name` teilt OpenSSL mit, welche Kurve verwendet werden soll. -* Der Parameter `-out` weist OpenSSL an, die Ausgabe in eine Datei zu schreiben. - -Beachten Sie, dass OpenSSL seine Ausgabe standardmäßig im PEM-Format schreibt. Wir können überprüfen, ob OpenSSL das Richtige tut, mit dem Befehl `ec`, der EC-Schlüssel verarbeitet: - -```bash -openssl ec -in privkey.pem -noout -text -``` - -* `-in` ist eine Eingabedatei -* Das `-noout` weist OpenSSL an, den Schlüssel nicht zu extrahieren, und gibt sinnlos privkey.pem nach stdout aus. -* `-text` weist OpenSSL an, Informationen über den Schlüssel im Klartextformat zu schreiben - -Wenn alles gut geht und der Schlüssel korrekt generiert wurde, zeigt OpenSSL etwa Folgendes: - -```text -read EC key -Private-Key: (384 bit) -priv: - [secret] -pub: - [secret] -ASN1 OID: secp384r1 -NIST CURVE: P-384 -``` - -Dadurch wird bestätigt, dass der Schlüssel mit der P-384-Kurve erstellt wurde. Wenn Sie sich fragen, warum wir nicht P-512 statt P-384 verwenden, Let's Encrypt signiert nicht, wenn die Ekliptikkurven höher als 384 Bit sind, und moderne Browser wie Google Chrome markieren Websites, die 512-Bit-Ekliptikkurven verwenden, als ungültig . Das ist die kurze Antwort. - -## Erstellen wir eine OpenSSL-Konfiguration für das Zertifikat - -Jetzt müssen wir eine OpenSSL-Konfigurationsdatei erstellen, die die domänenspezifischen Parameter enthält, für die wir das TLS-Zertifikat erhalten möchten. In diesem Beispiel tragen wir die folgende Konfiguration in eine `openssl.cnf`-Datei ein: - -```text -[ req ] -prompt = no -encrypt_key = no -default_md = sha512 -distinguished_name = dname -req_extensions = reqext - -[ dname ] -CN = example.com -emailAddress = admin@example.com - -[ reqext ] -subjectAltName = DNS:example.com, DNS:www.example.com -``` - -Hier ist eine kurze Beschreibung dieser Konfigurationsoptionen: - -Im erforderlichen `[ req ]`-Abschnitt: - -* `prompt=no` weist OpenSSL an, so viel Konfiguration wie möglich aus der Konfigurationsdatei zu holen -* `encrypt_key = no` weist OpenSSL an, den privaten Schlüssel nicht mit einem Passwort zu verschlüsseln. (Verschlüsselte private Schlüssel werden von Nginx unterstützt, aber ich verwende sie nicht.) -* `default_md=sha512` weist OpenSSL an, die CSR mit SHA512 zu signieren. (Soweit ich weiß, unterstützt Let's Encrypt nur RSA mit SHA256 für seine Signaturen, aber das bedeutet nicht, dass wir in CSR keine stärkere Verschlüsselung verwenden können.) -* `distinguished_name=dname` weist OpenSSL an, nach einem `[ dname ]`-Abschnitt für Konfigurationsoptionen für Distinguished Name zu suchen. -* „req_extensions=reqext“ weist OpenSSL an, in den Konfigurationsoptionen nach „Subject Alternative Names“ (SANs)-Erweiterungen, die es konfigurieren möchte, nach einem „[ reqext ]“-Abschnitt zu suchen. - -Im Abschnitt Distinguished Name `[ dname ]`: - -* „CN = example.com“ gibt den Common Name des Zertifikats an. -* Ihre `emailAddress = admin@example.com` E-Mail-Adresse muss prominent sein. -Gewünschte Erweiterungen Im Abschnitt „[ reqext ]“ stellt subjectAltName die Liste der SANs für das Zertifikat bereit. (Chrome ab v58 erfordert, dass der Common Name in der Liste der SANs enthalten ist). - -Let's Encrypt v2 unterstützt Platzhalterdomänen, daher können Sie in diesem Beispiel einen einstufigen Platzhalter für Nicht-Apex-Hosts (*.example.com) verwenden. - -## Lassen Sie uns eine Zertifikatsignieranforderung erstellen - -Der letzte Schritt auf der Client-Seite besteht darin, die Zertifikatsignieranforderung mit OpenSSL zu generieren, dann leiten wir sie zum Signieren an Let’s Encrypt weiter und rufen das signierte Zertifikat ab. - -Der zum Generieren einer CSR erforderliche OpenSSL-Befehl lautet `req` . - -```bash -openssl req -new -config openssl.cnf -key privkey.pem -out csr.pem -``` - -* `-new` teilt OpenSSL mit, dass wir eine CSR erstellt haben (und wir keine bestehende CSR untersuchen) -* `-config` openssl.cnf gibt die Konfigurationsdatei an, die wir oben erstellt haben -* `-key privkey.pem` gibt den privaten Schlüssel an, den wir oben erstellt haben -* `-out csr.pem` weist OpenSSL an, die CSR in eine Ausgabedatei zu schreiben (anstelle von stdout) - -Wir können überprüfen, ob wir die CSR korrekt erstellt haben: - -```bash -openssl req -in csr.pem -noout -text -verify -``` - -* `-verify` fordert OpenSSL auf, die Signatur in der CSR zu verifizieren - -Dies sollte die folgenden erwarteten Ergebnisse in der Ausgabe erzeugen: - -```text -verify OK -Certificate Request: - Data: - Version: 1 (0x0) - Subject: CN = example.com, emailAddress = admin@example.com - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (384 bit) - pub: - [ommited] - ASN1 OID: secp384r1 - NIST CURVE: P-384 - Attributes: - Requested Extensions: - X509v3 Subject Alternative Name: - DNS:example.com, DNS:www.example.com - Signature Algorithm: ecdsa-with-SHA512 - [ommited] -``` - -## Bitten Sie Let's Encrypt, unser Zertifikat zu signieren - -Der letzte Schritt besteht darin, die CSR mit einem ACME-Client zum Signieren an Let's Encrypt zu senden, "certbot" ist der häufigste Client für diesen Job. - -Befehlszeilenoptionen, die an den „Certbot“-Client übergeben werden, hängen von unserem Setup, der Person, für die unsere Domain registriert ist, usw. ab. Normalerweise müssen wir den Befehl "certonly" verwenden, und wenn Sie Sternchen (*) verwendet haben, müssen Sie eines der certbot-DNS-Plugins verwenden. - -Ist beispielsweise die Domain „example.com“ bei Cloudflare registriert, können wir die Verifizierung über das entsprechende Plugin durchführen, was äußerst komfortabel ist und keinen manuellen Eingriff in den Vorgang erfordert. (Das Konfigurieren des Cloudflare-Plugins mit geheimen Token-Informationen würde den Rahmen dieses Artikels sprengen.) - -Es wird normalerweise empfohlen, zuerst mit `--dry-run` sicherzustellen, dass alles in Ordnung ist, um sicherzustellen, dass alles in Ordnung ist. - -```bash -certbot nginx certonly --dry-run --domain "example.com" --domain "www.example.com" --csr csr.pem -``` - -* Anführungszeichen sind um Zeichen herum erforderlich, um fehlerhafte Manipulationen zu vermeiden, und sind im Allgemeinen eine gute Idee. -* `--csr csr.pem` teilt certbot mit, dass wir bereits ein Zertifikat haben und Let’s Encrypt benötigen, um es für uns zu signieren. - -Der Certbot-Client überprüft auf der Befehlszeile, ob die angeforderte Liste der Domänen mit den im Zertifikat aufgeführten Domänen übereinstimmt, und verwendet das Certbot-NGINX-Plug-in, um zu überprüfen, ob die Domäne unsere ist, und teilt uns mit, falls es Probleme gibt. - -Wenn nichts falsch ist, wird es Ihnen sagen: - -```text -WICHTIGE NOTIZEN: - - Der Probelauf war erfolgreich. -``` - -Der eigentliche Befehl lautet wie folgt: - -```bash -certbot nginx certonly --domain "example.com" --domain "www.example.com" --csr csr.pem -``` - -Nach einer (langen) Verzögerung gibt der Client Folgendes aus: - -1. Signiertes Zertifikat: `0000_cert.pem` -2. Stamm- und Zwischenzertifikate: „0000_chain.pem“. -3. Zertifikat + Zwischenprodukte: `0001_chain.pem` -An dieser Stelle kann die CSR `csr.pem` gelöscht werden. - -Wenn wir neugierig sind, können wir die vom Client zurückgegebenen Zertifikate mit OpenSSL mit dem Befehl "x509" überprüfen: - -```bash -openssl x509 -in 0001_chain.pem -noout -text -``` - -Leider werden wir feststellen, dass Let’s Encrypt wie oben beschrieben unser Zertifikat mit einer SHA256-Signatur signiert. (SHA512 ist nicht nur sicherer, sondern übertrifft SHA256 auf modernen 64-Bit-CPUs.) Aber unser öffentlicher Schlüssel sollte immer noch ECDSA verwenden. - -Diese Dateien sind nicht gewöhnlich, daher müssen wir sie auf informativere Weise verschieben und bearbeiten. - -Unter Debian Linux erstelle ich gerne Unterverzeichnisse für meine Domains, indem ich meinen privaten Schlüssel in `/home/USER_NAME/SSL/private/example.com/privkey.pem` und Zertifikate behalte: - -* `/home/USER_NAME/SSL/certs/example.com/cert.pem` -* `/home/USER_NAME/SSL/certs/example.com/chain.pem` -* `/home/USER_NAME/SSL/certs/example.com/fullchain.pem` - -# ENDE - -Wenn wir alles richtig gemacht haben, bestätigt die Überprüfung des Zertifikats mit einem Webbrowser wie Chrome, dass es sich um ein EC-Zertifikat handelt: - -![https://dev.to/benjaminblack/obtaining-an-elliptic-curve-dsa-certificate-with-lets-encrypt-51bc (Datum: 08.04.2023)](/images/ecc-ssl/ecc-sll-key-chrome.png) - -Mozilla Observatory wird uns auch eine A+ Bewertung geben! - -![https://dev.to/benjaminblack/obtaining-an-elliptic-curve-dsa-certificate-with-lets-encrypt-51bc (Datum: 08.04.2023)](/images/ecc-ssl/ecc-ssl-key-mozilla.png) - -Darüber hinaus können wir als Ergebnis des SSL Labs-Berichts sehen, dass ein 384-Bit-ECC-Zertifikat verwendet wurde. - -![SSL Labs Test](/images/ecc-ssl/ecc-ssl-key-ssllabs.png) - -HINWEIS: Dieser Artikel profitiert vom Artikel von [Benjamin Black](https://dev.to/benjaminblack/obtaining-an-elliptic-curve-dsa-certificate-with-lets-encrypt-51bc) zum gleichen Thema. +--- +title: "Generieren eines ECC-SSL-Zertifikats auf einem Linux-Server" +date: 2022-03-20 +tags: ["linux", "ssl", "sicherheit", "ecc", "elliptische kurve"] +author: "Wise" +draft: false +--- +# Einführung und Zusammenfassung + +Heute lernen wir, wie man SSL-Zertifikate generiert, um sicherzustellen, dass der Datenverkehr zwischen einer von Ihnen verwalteten Website oder einem Anwendungsserver und Ihren Besuchern vertraulich / zuverlässig und überprüfbar ist. In meinen vorherigen Artikeln habe ich erklärt, wie und mit welcher Konfiguration Sie das von Ihnen erstellte Zertifikat bereitstellen würden. In diesem Artikel zeige ich Ihnen, wie Sie die Gleichung „weniger Brot, mehr Frikadellen“ aufstellen, also ein schnelleres und sichereres SSL-Zertifikat erstellen. Wenn Sie mit dem ACME-Protokoll von Let’s Encrypt vertraut sind (zum Zeitpunkt des Schreibens), ist es normalerweise möglich, ein 1024-4098 (wenn Sie sich zu sehr anstrengen, vielleicht 8196) Bit-Zertifikat mit einer asymmetrischen RSA-Schlüsselstruktur zu generieren und es für zu verwenden 90 Tage relativ. Das Generieren eines so großen Schlüssels, dessen Verwendung während des TLS-Handshakes nach der Generierung und die Kompatibilität mit den von den Besuchern verwendeten Geräten verursachen jedoch in den meisten Szenarien Probleme. Wenn beispielsweise 4096 Bit anstelle von 2048 Bit verwendet werden, bin ich bei einigen meiner Versuche mit 0,4-0,8 Sekunden längeren Handshake-Zeiten konfrontiert. Als ob es in Ordnung wäre, dass der Handshake so lange dauert, wird der Server dadurch zusätzlich belastet. Aber wenn Sie ein 384-Bit-ECC-Zertifikat anstelle von 4096-Bit-RSA generieren, erhalten Sie ein viel schnelleres Zertifikat und gleichzeitig eine Sicherheit, die 7680-Bit-RSA entspricht (wenn es diese Größe hätte). + +Nun, Sie haben es gut erklärt, aber wo ist der Sinn dieser Arbeit, scheine ich Sie sagen zu hören. Ich werde Sie verärgern, aber dieses Geschäft hat keinen Sinn. Der Grund, warum dies nicht der Fall ist, ist in der Hintergrundmathematik verborgen. Ich werde kurz auf die kleinen Unterschiede in der Herstellung und Verwendung beider Zertifikate eingehen, erklären, wie und warum sie große Unterschiede verursachen, und im letzten Teil werde ich über etwas sprechen, das nicht als Bonus im Titel steht. (Für den Bonus musst du bis zum Ende lesen :D) + +![https://www.globalsign.com/en/blog/elliptic-curve-cryptography (Datum: 08.04.2023)](/images/ecc-ssl/key-size-comparison.jpg) + +## Produktionsprozess des ECC-Zertifikats + +Zuerst müssen wir (wie immer) die neuesten Updates über die Konsole mit dem Paketmanager der Linux-Version installieren, in der wir uns befinden. + +```bash +Ubuntu: sudo apt update && sudo apt upgrade -y + +Fedora: sudo yum update -y + +Arch Linux: sudo pacman -Syyu +``` + +Nachdem die Updates installiert sind, beginnen wir mit der Konfiguration des nginx-Dienstes (das ist der Dienst, der es Ihnen ermöglicht, externe HTTP/HTTPS-Verbindungen zu empfangen) auf Ihrem Server (in meinem Fall Ubuntu). Zunächst einmal sollte angemerkt werden, dass es sich aufgrund der Verwirrung bei Apache-, Nginx- und Litespeed-Diensten um unterschiedliche Dienste handelt, die die gleiche Aufgabe erfüllen. Ich habe mich für NGINX entschieden, weil es einfacher zu verwalten ist und mehr Community-Unterstützung bietet. + +## Lassen Sie uns den privaten Schlüssel generieren + +Zuerst generieren wir den privaten Schlüssel mit OpenSSL. Der OpenSSL-Befehl, den wir verwenden werden, ist „ecparam“ (EC-Parametermanipulation) und um die Konfigurationsparameter an diesen Befehl zu übergeben: + +```bash +openssl ecparam -genkey -name secp384r1 -out privkey.pem +``` + +* Die Option `-genkey` weist OpenSSL an, einen EC-Schlüssel zu generieren. +* Der Parameter `-name` teilt OpenSSL mit, welche Kurve verwendet werden soll. +* Der Parameter `-out` weist OpenSSL an, die Ausgabe in eine Datei zu schreiben. + +Beachten Sie, dass OpenSSL seine Ausgabe standardmäßig im PEM-Format schreibt. Wir können überprüfen, ob OpenSSL das Richtige tut, mit dem Befehl `ec`, der EC-Schlüssel verarbeitet: + +```bash +openssl ec -in privkey.pem -noout -text +``` + +* `-in` ist eine Eingabedatei +* Das `-noout` weist OpenSSL an, den Schlüssel nicht zu extrahieren, und gibt sinnlos privkey.pem nach stdout aus. +* `-text` weist OpenSSL an, Informationen über den Schlüssel im Klartextformat zu schreiben + +Wenn alles gut geht und der Schlüssel korrekt generiert wurde, zeigt OpenSSL etwa Folgendes: + +```text +read EC key +Private-Key: (384 bit) +priv: + [secret] +pub: + [secret] +ASN1 OID: secp384r1 +NIST CURVE: P-384 +``` + +Dadurch wird bestätigt, dass der Schlüssel mit der P-384-Kurve erstellt wurde. Wenn Sie sich fragen, warum wir nicht P-512 statt P-384 verwenden, Let's Encrypt signiert nicht, wenn die Ekliptikkurven höher als 384 Bit sind, und moderne Browser wie Google Chrome markieren Websites, die 512-Bit-Ekliptikkurven verwenden, als ungültig . Das ist die kurze Antwort. + +## Erstellen wir eine OpenSSL-Konfiguration für das Zertifikat + +Jetzt müssen wir eine OpenSSL-Konfigurationsdatei erstellen, die die domänenspezifischen Parameter enthält, für die wir das TLS-Zertifikat erhalten möchten. In diesem Beispiel tragen wir die folgende Konfiguration in eine `openssl.cnf`-Datei ein: + +```text +[ req ] +prompt = no +encrypt_key = no +default_md = sha512 +distinguished_name = dname +req_extensions = reqext + +[ dname ] +CN = example.com +emailAddress = admin@example.com + +[ reqext ] +subjectAltName = DNS:example.com, DNS:www.example.com +``` + +Hier ist eine kurze Beschreibung dieser Konfigurationsoptionen: + +Im erforderlichen `[ req ]`-Abschnitt: + +* `prompt=no` weist OpenSSL an, so viel Konfiguration wie möglich aus der Konfigurationsdatei zu holen +* `encrypt_key = no` weist OpenSSL an, den privaten Schlüssel nicht mit einem Passwort zu verschlüsseln. (Verschlüsselte private Schlüssel werden von Nginx unterstützt, aber ich verwende sie nicht.) +* `default_md=sha512` weist OpenSSL an, die CSR mit SHA512 zu signieren. (Soweit ich weiß, unterstützt Let's Encrypt nur RSA mit SHA256 für seine Signaturen, aber das bedeutet nicht, dass wir in CSR keine stärkere Verschlüsselung verwenden können.) +* `distinguished_name=dname` weist OpenSSL an, nach einem `[ dname ]`-Abschnitt für Konfigurationsoptionen für Distinguished Name zu suchen. +* „req_extensions=reqext“ weist OpenSSL an, in den Konfigurationsoptionen nach „Subject Alternative Names“ (SANs)-Erweiterungen, die es konfigurieren möchte, nach einem „[ reqext ]“-Abschnitt zu suchen. + +Im Abschnitt Distinguished Name `[ dname ]`: + +* „CN = example.com“ gibt den Common Name des Zertifikats an. +* Ihre `emailAddress = admin@example.com` E-Mail-Adresse muss prominent sein. +Gewünschte Erweiterungen Im Abschnitt „[ reqext ]“ stellt subjectAltName die Liste der SANs für das Zertifikat bereit. (Chrome ab v58 erfordert, dass der Common Name in der Liste der SANs enthalten ist). + +Let's Encrypt v2 unterstützt Platzhalterdomänen, daher können Sie in diesem Beispiel einen einstufigen Platzhalter für Nicht-Apex-Hosts (*.example.com) verwenden. + +## Lassen Sie uns eine Zertifikatsignieranforderung erstellen + +Der letzte Schritt auf der Client-Seite besteht darin, die Zertifikatsignieranforderung mit OpenSSL zu generieren, dann leiten wir sie zum Signieren an Let’s Encrypt weiter und rufen das signierte Zertifikat ab. + +Der zum Generieren einer CSR erforderliche OpenSSL-Befehl lautet `req` . + +```bash +openssl req -new -config openssl.cnf -key privkey.pem -out csr.pem +``` + +* `-new` teilt OpenSSL mit, dass wir eine CSR erstellt haben (und wir keine bestehende CSR untersuchen) +* `-config` openssl.cnf gibt die Konfigurationsdatei an, die wir oben erstellt haben +* `-key privkey.pem` gibt den privaten Schlüssel an, den wir oben erstellt haben +* `-out csr.pem` weist OpenSSL an, die CSR in eine Ausgabedatei zu schreiben (anstelle von stdout) + +Wir können überprüfen, ob wir die CSR korrekt erstellt haben: + +```bash +openssl req -in csr.pem -noout -text -verify +``` + +* `-verify` fordert OpenSSL auf, die Signatur in der CSR zu verifizieren + +Dies sollte die folgenden erwarteten Ergebnisse in der Ausgabe erzeugen: + +```text +verify OK +Certificate Request: + Data: + Version: 1 (0x0) + Subject: CN = example.com, emailAddress = admin@example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + [ommited] + ASN1 OID: secp384r1 + NIST CURVE: P-384 + Attributes: + Requested Extensions: + X509v3 Subject Alternative Name: + DNS:example.com, DNS:www.example.com + Signature Algorithm: ecdsa-with-SHA512 + [ommited] +``` + +## Bitten Sie Let's Encrypt, unser Zertifikat zu signieren + +Der letzte Schritt besteht darin, die CSR mit einem ACME-Client zum Signieren an Let's Encrypt zu senden, "certbot" ist der häufigste Client für diesen Job. + +Befehlszeilenoptionen, die an den „Certbot“-Client übergeben werden, hängen von unserem Setup, der Person, für die unsere Domain registriert ist, usw. ab. Normalerweise müssen wir den Befehl "certonly" verwenden, und wenn Sie Sternchen (*) verwendet haben, müssen Sie eines der certbot-DNS-Plugins verwenden. + +Ist beispielsweise die Domain „example.com“ bei Cloudflare registriert, können wir die Verifizierung über das entsprechende Plugin durchführen, was äußerst komfortabel ist und keinen manuellen Eingriff in den Vorgang erfordert. (Das Konfigurieren des Cloudflare-Plugins mit geheimen Token-Informationen würde den Rahmen dieses Artikels sprengen.) + +Es wird normalerweise empfohlen, zuerst mit `--dry-run` sicherzustellen, dass alles in Ordnung ist, um sicherzustellen, dass alles in Ordnung ist. + +```bash +certbot nginx certonly --dry-run --domain "example.com" --domain "www.example.com" --csr csr.pem +``` + +* Anführungszeichen sind um Zeichen herum erforderlich, um fehlerhafte Manipulationen zu vermeiden, und sind im Allgemeinen eine gute Idee. +* `--csr csr.pem` teilt certbot mit, dass wir bereits ein Zertifikat haben und Let’s Encrypt benötigen, um es für uns zu signieren. + +Der Certbot-Client überprüft auf der Befehlszeile, ob die angeforderte Liste der Domänen mit den im Zertifikat aufgeführten Domänen übereinstimmt, und verwendet das Certbot-NGINX-Plug-in, um zu überprüfen, ob die Domäne unsere ist, und teilt uns mit, falls es Probleme gibt. + +Wenn nichts falsch ist, wird es Ihnen sagen: + +```text +WICHTIGE NOTIZEN: + - Der Probelauf war erfolgreich. +``` + +Der eigentliche Befehl lautet wie folgt: + +```bash +certbot nginx certonly --domain "example.com" --domain "www.example.com" --csr csr.pem +``` + +Nach einer (langen) Verzögerung gibt der Client Folgendes aus: + +1. Signiertes Zertifikat: `0000_cert.pem` +2. Stamm- und Zwischenzertifikate: „0000_chain.pem“. +3. Zertifikat + Zwischenprodukte: `0001_chain.pem` +An dieser Stelle kann die CSR `csr.pem` gelöscht werden. + +Wenn wir neugierig sind, können wir die vom Client zurückgegebenen Zertifikate mit OpenSSL mit dem Befehl "x509" überprüfen: + +```bash +openssl x509 -in 0001_chain.pem -noout -text +``` + +Leider werden wir feststellen, dass Let’s Encrypt wie oben beschrieben unser Zertifikat mit einer SHA256-Signatur signiert. (SHA512 ist nicht nur sicherer, sondern übertrifft SHA256 auf modernen 64-Bit-CPUs.) Aber unser öffentlicher Schlüssel sollte immer noch ECDSA verwenden. + +Diese Dateien sind nicht gewöhnlich, daher müssen wir sie auf informativere Weise verschieben und bearbeiten. + +Unter Debian Linux erstelle ich gerne Unterverzeichnisse für meine Domains, indem ich meinen privaten Schlüssel in `/home/USER_NAME/SSL/private/example.com/privkey.pem` und Zertifikate behalte: + +* `/home/USER_NAME/SSL/certs/example.com/cert.pem` +* `/home/USER_NAME/SSL/certs/example.com/chain.pem` +* `/home/USER_NAME/SSL/certs/example.com/fullchain.pem` + +# ENDE + +Wenn wir alles richtig gemacht haben, bestätigt die Überprüfung des Zertifikats mit einem Webbrowser wie Chrome, dass es sich um ein EC-Zertifikat handelt: + +![https://dev.to/benjaminblack/obtaining-an-elliptic-curve-dsa-certificate-with-lets-encrypt-51bc (Datum: 08.04.2023)](/images/ecc-ssl/ecc-sll-key-chrome.png) + +Mozilla Observatory wird uns auch eine A+ Bewertung geben! + +![https://dev.to/benjaminblack/obtaining-an-elliptic-curve-dsa-certificate-with-lets-encrypt-51bc (Datum: 08.04.2023)](/images/ecc-ssl/ecc-ssl-key-mozilla.png) + +Darüber hinaus können wir als Ergebnis des SSL Labs-Berichts sehen, dass ein 384-Bit-ECC-Zertifikat verwendet wurde. + +![SSL Labs Test](/images/ecc-ssl/ecc-ssl-key-ssllabs.png) + +HINWEIS: Dieser Artikel profitiert vom Artikel von [Benjamin Black](https://dev.to/benjaminblack/obtaining-an-elliptic-curve-dsa-certificate-with-lets-encrypt-51bc) zum gleichen Thema. diff --git a/content/post/ecc-ssl-sertifikasi.en.md b/content/post/ecc-ssl-sertifikasi.en.md index 0305cd9a..65a7964f 100644 --- a/content/post/ecc-ssl-sertifikasi.en.md +++ b/content/post/ecc-ssl-sertifikasi.en.md @@ -1,220 +1,220 @@ ---- -title: "Generating ECC SSL Certificate on Linux Server" -date: 2022-03-20 -tags: ["linux", "ssl", "security", "ecc", "elliptic curve"] -author: "Wise" -draft: false ---- -# Introduction and Summary - -Today we will learn how to generate SSL certificates to ensure that the traffic between a website or application server you manage and your visitors is confidential / reliable and verifiable. In my previous articles, I explained how and with what configuration you would deploy the certificate you produced. In this article, I will show you how to set up the equation of less bread, more meatballs, that is, how to produce a faster and more secure SSL certificate. Normally, if you are familiar with Let's Encrypt's ACME protocol (as of the date of writing), it is possible to generate a 1024-4098 (if you try too hard, maybe 8196) bit certificate with RSA asymmetric key structure and use it for 90 days relatively. However, generating such a large key, using it during TLS handshake after generating it, and being compatible with the devices used by the visitors causes problems in most scenarios. For example, when 4096 bits are used instead of 2048 bits, I am faced with 0.4-0.8 seconds longer handshake times in some of my attempts. As if it's okay for the handshake to take that long, it puts an extra load on the server. But when you generate a 384-bit ECC certificate instead of 4096-bit RSA, you get a much faster certificate and at the same time security equal to 7680-bit RSA (if it were that size). - -Well, you explained it well, but where is the point of this work, I seem to hear you say. I will upset you, but there is no point in this business. The reason why it doesn't is hidden in the background math. Briefly, I will talk about the minor differences in the production and use of both certificates, explain how and why they cause big differences, and in the last part, I will talk about something that is not written in the title as a bonus. (For the bonus you'll have to read till the end :D) - -![https://www.globalsign.com/en/blog/elliptic-curve-cryptography (Date: 08.04.2023)](/images/ecc-ssl/key-size-comparison.jpg) - -## Production process of ECC Certificate - -First of all (as always), we need to install the latest updates via the console with the package manager of the Linux version we are in. - -```bash -Ubuntu: sudo apt update && sudo apt upgrade -y - -Fedora: sudo yum update -y - -Arch Linux: sudo pacman -Syyu -``` - -After the updates are installed, we start configuring the nginx service (which is the service that allows you to receive external HTTP/HTTPS connections) on your server (Ubuntu in my case). First of all, it should be noted that because of the confusion, apache, nginx and litespeed services are different services that do the same job. I chose NGINX because it is easier to manage and has more community support. - -## Let's generate the private key - -First, we generate the private key with OpenSSL. The OpenSSL command we will use is 'ecparam' (EC parameter manipulation) and to pass the configuration parameters to this command: - -```bash -openssl ecparam -genkey -name secp384r1 -out privkey.pem -``` - -* The `-genkey` option tells OpenSSL to generate an EC key. -* The `-name` parameter tells OpenSSL which curve to use. -* The `-out` parameter tells OpenSSL to write the output to a file. - -Note that OpenSSL writes its output in PEM format by default. We can check that OpenSSL is doing the right thing with the `ec` command that handles EC keys: - -```bash -openssl ec -in privkey.pem -noout -text -``` - -* `-in` is input file -* The `-noout` tells OpenSSL not to extract the key, meaninglessly printing privkey.pem to stdout. -* `-text` tells OpenSSL to write information about the key in plain text format - -If all goes well and the key is generated correctly, OpenSSL will show something like the following: - -```text -read EC key -Private-Key: (384 bit) -priv: - [secret] -pub: - [secret] -ASN1 OID: secp384r1 -NIST CURVE: P-384 -``` - -This verifies that the key was created with the P-384 curve. If you ask why we don't use P-512 instead of P-384, Let's Encrypt doesn't sign if the ecliptic curves are higher than 384 bits, and modern browsers like Google Chrome mark websites using 512-bit ecliptic curves as invalid. That's the short answer. - -## Let's create OpenSSL configuration for the certificate - -Now we need to create an OpenSSL configuration file containing the domain-specific parameters for which we want to get the TLS certificate. In this example, we will enter the following configuration in an `openssl.cnf` file: - -```text -[ req ] -prompt = no -encrypt_key = no -default_md = sha512 -distinguished_name = dname -req_extensions = reqext - -[ dname ] -CN = example.com -emailAddress = admin@example.com - -[ reqext ] -subjectAltName = DNS:example.com, DNS:www.example.com -``` - -Here is a brief description of these configuration options: - -In the required `[ req ]` section: - -* `prompt=no` tells OpenSSL to get as much configuration as possible from the config file -* `encrypt_key = no` tells OpenSSL not to encrypt the private key with a password. (Encrypted private keys are supported by Nginx, but I don't use them.) -* `default_md=sha512` tells OpenSSL to sign the CSR with SHA512. (As far as I know, Let's Encrypt only supports RSA with SHA256 for its signatures, but that doesn't mean we can't use stronger encryption in CSR.) -* `distinguished_name=dname` tells OpenSSL to look for a `[ dname ]` section for Distinguished Name configuration options. -* `req_extensions=reqext` tells OpenSSL to look for a `[ reqext ]` section in the configuration options for Subject Alternative Names (SANs) extensions that it wants to configure. - -In the Distinguished Name `[ dname ]` section: - -* `CN = example.com` indicates the Common Name of the certificate. -* Your `emailAddress = admin@example.com` email address must be prominent. -Desired Extensions In the `[ reqext ]` section, subjectAltName provides the list of SANs for the certificate. (Chrome as of v58 requires that the Common Name be included in the list of SANs). - -Let's Encrypt v2 supports wildcard domains, so in this example you can use a single-level wildcard for non-apex hosts (*.example.com). - -## Let's Create Certificate Signing Request - -The final step on the client side is to generate the Certificate Signing Request using OpenSSL, then we will forward it to Let's Encrypt for signing and retrieve the signed certificate. - -The OpenSSL command required to generate a CSR is `req` . - -```bash -openssl req -new -config openssl.cnf -key privkey.pem -out csr.pem -``` - -* `-new` tells OpenSSL that we have created a CSR (and we do not examine an existing CSR) -* `-config` openssl.cnf specifies the config file we created above -* `-key privkey.pem` indicates the private key we created above -* `-out csr.pem` tells OpenSSL to write the CSR to an output file (instead of stdout) - -We can verify that we have generated the CSR correctly: - -```bash -openssl req -in csr.pem -noout -text -verify -``` - -* `-verify` asks OpenSSL to verify the signature in the CSR - -This should produce the following expected results in the output: - -```text -verify OK -Certificate Request: - Data: - Version: 1 (0x0) - Subject: CN = example.com, emailAddress = admin@example.com - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (384 bit) - pub: - [gizli] - ASN1 OID: secp384r1 - NIST CURVE: P-384 - Attributes: - Requested Extensions: - X509v3 Subject Alternative Name: - DNS:example.com, DNS:www.example.com - Signature Algorithm: ecdsa-with-SHA512 - [gizli] -``` - -## Ask Let's Encrypt to sign our certificate - -The final step is to send the CSR with an ACME client to Let's Encrypt for signing, `certbot` is the most common client for this job. - -Command line options passed to the `Certbot` client depend on our setup, the person our domain is registered to, etc. varies depending. Usually we need to use the `certonly` command and if you used asterisks (*) you need to use one of the certbot DNS plugins. - -For example, if the domain `example.com` is registered with Cloudflare, we can use the corresponding plugin to handle the verification, which is extremely convenient and does not require manual intervention in the process. (Configuring the Cloudflare plugin with secret token information is beyond the scope of this article.) - -It's usually recommended to make sure everything is ok with `--dry-run` first to make sure everything is ok. - -```bash -certbot nginx certonly --dry-run --domain "example.com" --domain "www.example.com" --csr csr.pem -``` - -* Quotation marks are required around characters to avoid erroneous manipulations and are generally a good idea. -* `--csr csr.pem` tells certbot that we already have a certificate and we need Let's Encrypt to sign it for us. - -The Certbot client will check on the command line that the requested list of domains matches the domains listed in the certificate and will use the Certbot NGINX plugin to verify that the domain is ours and let us know if there are any issues. - -If nothing is wrong, it will tell you: - -```text -IMPORTANT NOTES: - - The dry run was successful. -``` - -The actual command is just as follows: - -```bash -certbot nginx certonly --domain "example.com" --domain "www.example.com" --csr csr.pem -``` - -After a (long) delay, the client will output: - -1. Signed certificate: `0000_cert.pem` -2. Root and intermediate certificates: `0000_chain.pem` -3. Certificate + intermediates: `0001_chain.pem` -At this point, the CSR `csr.pem` can be deleted. - -If we are curious, we can inspect the certificates returned by the client with OpenSSL using the `x509` command: - -```bash -openssl x509 -in 0001_chain.pem -noout -text -``` - -Unfortunately, we will discover that as described above, Let's Encrypt signs our certificate with a SHA256 signature. (As well as being more secure, SHA512 outperforms SHA256 on modern 64-bit CPUs.) But our public key should still use ECDSA. - -These files are not ordinary, so we must move and edit them in a more informative way. - -On Debian Linux I like to create subdirectories for my domains by keeping my private key in `/home/USER_NAME/SSL/private/example.com/privkey.pem` and certificates: - -* `/home/USER_NAME/SSL/certs/example.com/cert.pem` -* `/home/USER_NAME/SSL/certs/example.com/chain.pem` -* `/home/USER_NAME/SSL/certs/example.com/fullchain.pem` - -# END - -If we've done everything right, inspecting the certificate with a web browser like Chrome will confirm that it's an EC certificate: - -![https://dev.to/benjaminblack/obtaining-an-elliptic-curve-dsa-certificate-with-lets-encrypt-51bc (Date: 08.04.2023)](/images/ecc-ssl/ecc-sll-key-chrome.png) - -Mozilla Observatory will also give us an A+ rating! - -![https://dev.to/benjaminblack/obtaining-an-elliptic-curve-dsa-certificate-with-lets-encrypt-51bc (Date: 08.04.2023)](/images/ecc-ssl/ecc-ssl-key-mozilla.png) - -In addition, we can see that a 384-bit ECC certificate was used as a result of the SSL Labs report. - -![SSL Labs Test Result](/images/ecc-ssl/ecc-ssl-key-ssllabs.png) - -NOTE: This article has benefited from the article of [Benjamin Black](https://dev.to/benjaminblack/obtaining-an-elliptic-curve-dsa-certificate-with-lets-encrypt-51bc) on the same subject. +--- +title: "Generating ECC SSL Certificate on Linux Server" +date: 2022-03-20 +tags: ["linux", "ssl", "security", "ecc", "elliptic curve"] +author: "Wise" +draft: false +--- +# Introduction and Summary + +Today we will learn how to generate SSL certificates to ensure that the traffic between a website or application server you manage and your visitors is confidential / reliable and verifiable. In my previous articles, I explained how and with what configuration you would deploy the certificate you produced. In this article, I will show you how to set up the equation of less bread, more meatballs, that is, how to produce a faster and more secure SSL certificate. Normally, if you are familiar with Let's Encrypt's ACME protocol (as of the date of writing), it is possible to generate a 1024-4098 (if you try too hard, maybe 8196) bit certificate with RSA asymmetric key structure and use it for 90 days relatively. However, generating such a large key, using it during TLS handshake after generating it, and being compatible with the devices used by the visitors causes problems in most scenarios. For example, when 4096 bits are used instead of 2048 bits, I am faced with 0.4-0.8 seconds longer handshake times in some of my attempts. As if it's okay for the handshake to take that long, it puts an extra load on the server. But when you generate a 384-bit ECC certificate instead of 4096-bit RSA, you get a much faster certificate and at the same time security equal to 7680-bit RSA (if it were that size). + +Well, you explained it well, but where is the point of this work, I seem to hear you say. I will upset you, but there is no point in this business. The reason why it doesn't is hidden in the background math. Briefly, I will talk about the minor differences in the production and use of both certificates, explain how and why they cause big differences, and in the last part, I will talk about something that is not written in the title as a bonus. (For the bonus you'll have to read till the end :D) + +![https://www.globalsign.com/en/blog/elliptic-curve-cryptography (Date: 08.04.2023)](/images/ecc-ssl/key-size-comparison.jpg) + +## Production process of ECC Certificate + +First of all (as always), we need to install the latest updates via the console with the package manager of the Linux version we are in. + +```bash +Ubuntu: sudo apt update && sudo apt upgrade -y + +Fedora: sudo yum update -y + +Arch Linux: sudo pacman -Syyu +``` + +After the updates are installed, we start configuring the nginx service (which is the service that allows you to receive external HTTP/HTTPS connections) on your server (Ubuntu in my case). First of all, it should be noted that because of the confusion, apache, nginx and litespeed services are different services that do the same job. I chose NGINX because it is easier to manage and has more community support. + +## Let's generate the private key + +First, we generate the private key with OpenSSL. The OpenSSL command we will use is 'ecparam' (EC parameter manipulation) and to pass the configuration parameters to this command: + +```bash +openssl ecparam -genkey -name secp384r1 -out privkey.pem +``` + +* The `-genkey` option tells OpenSSL to generate an EC key. +* The `-name` parameter tells OpenSSL which curve to use. +* The `-out` parameter tells OpenSSL to write the output to a file. + +Note that OpenSSL writes its output in PEM format by default. We can check that OpenSSL is doing the right thing with the `ec` command that handles EC keys: + +```bash +openssl ec -in privkey.pem -noout -text +``` + +* `-in` is input file +* The `-noout` tells OpenSSL not to extract the key, meaninglessly printing privkey.pem to stdout. +* `-text` tells OpenSSL to write information about the key in plain text format + +If all goes well and the key is generated correctly, OpenSSL will show something like the following: + +```text +read EC key +Private-Key: (384 bit) +priv: + [secret] +pub: + [secret] +ASN1 OID: secp384r1 +NIST CURVE: P-384 +``` + +This verifies that the key was created with the P-384 curve. If you ask why we don't use P-512 instead of P-384, Let's Encrypt doesn't sign if the ecliptic curves are higher than 384 bits, and modern browsers like Google Chrome mark websites using 512-bit ecliptic curves as invalid. That's the short answer. + +## Let's create OpenSSL configuration for the certificate + +Now we need to create an OpenSSL configuration file containing the domain-specific parameters for which we want to get the TLS certificate. In this example, we will enter the following configuration in an `openssl.cnf` file: + +```text +[ req ] +prompt = no +encrypt_key = no +default_md = sha512 +distinguished_name = dname +req_extensions = reqext + +[ dname ] +CN = example.com +emailAddress = admin@example.com + +[ reqext ] +subjectAltName = DNS:example.com, DNS:www.example.com +``` + +Here is a brief description of these configuration options: + +In the required `[ req ]` section: + +* `prompt=no` tells OpenSSL to get as much configuration as possible from the config file +* `encrypt_key = no` tells OpenSSL not to encrypt the private key with a password. (Encrypted private keys are supported by Nginx, but I don't use them.) +* `default_md=sha512` tells OpenSSL to sign the CSR with SHA512. (As far as I know, Let's Encrypt only supports RSA with SHA256 for its signatures, but that doesn't mean we can't use stronger encryption in CSR.) +* `distinguished_name=dname` tells OpenSSL to look for a `[ dname ]` section for Distinguished Name configuration options. +* `req_extensions=reqext` tells OpenSSL to look for a `[ reqext ]` section in the configuration options for Subject Alternative Names (SANs) extensions that it wants to configure. + +In the Distinguished Name `[ dname ]` section: + +* `CN = example.com` indicates the Common Name of the certificate. +* Your `emailAddress = admin@example.com` email address must be prominent. +Desired Extensions In the `[ reqext ]` section, subjectAltName provides the list of SANs for the certificate. (Chrome as of v58 requires that the Common Name be included in the list of SANs). + +Let's Encrypt v2 supports wildcard domains, so in this example you can use a single-level wildcard for non-apex hosts (*.example.com). + +## Let's Create Certificate Signing Request + +The final step on the client side is to generate the Certificate Signing Request using OpenSSL, then we will forward it to Let's Encrypt for signing and retrieve the signed certificate. + +The OpenSSL command required to generate a CSR is `req` . + +```bash +openssl req -new -config openssl.cnf -key privkey.pem -out csr.pem +``` + +* `-new` tells OpenSSL that we have created a CSR (and we do not examine an existing CSR) +* `-config` openssl.cnf specifies the config file we created above +* `-key privkey.pem` indicates the private key we created above +* `-out csr.pem` tells OpenSSL to write the CSR to an output file (instead of stdout) + +We can verify that we have generated the CSR correctly: + +```bash +openssl req -in csr.pem -noout -text -verify +``` + +* `-verify` asks OpenSSL to verify the signature in the CSR + +This should produce the following expected results in the output: + +```text +verify OK +Certificate Request: + Data: + Version: 1 (0x0) + Subject: CN = example.com, emailAddress = admin@example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + [gizli] + ASN1 OID: secp384r1 + NIST CURVE: P-384 + Attributes: + Requested Extensions: + X509v3 Subject Alternative Name: + DNS:example.com, DNS:www.example.com + Signature Algorithm: ecdsa-with-SHA512 + [gizli] +``` + +## Ask Let's Encrypt to sign our certificate + +The final step is to send the CSR with an ACME client to Let's Encrypt for signing, `certbot` is the most common client for this job. + +Command line options passed to the `Certbot` client depend on our setup, the person our domain is registered to, etc. varies depending. Usually we need to use the `certonly` command and if you used asterisks (*) you need to use one of the certbot DNS plugins. + +For example, if the domain `example.com` is registered with Cloudflare, we can use the corresponding plugin to handle the verification, which is extremely convenient and does not require manual intervention in the process. (Configuring the Cloudflare plugin with secret token information is beyond the scope of this article.) + +It's usually recommended to make sure everything is ok with `--dry-run` first to make sure everything is ok. + +```bash +certbot nginx certonly --dry-run --domain "example.com" --domain "www.example.com" --csr csr.pem +``` + +* Quotation marks are required around characters to avoid erroneous manipulations and are generally a good idea. +* `--csr csr.pem` tells certbot that we already have a certificate and we need Let's Encrypt to sign it for us. + +The Certbot client will check on the command line that the requested list of domains matches the domains listed in the certificate and will use the Certbot NGINX plugin to verify that the domain is ours and let us know if there are any issues. + +If nothing is wrong, it will tell you: + +```text +IMPORTANT NOTES: + - The dry run was successful. +``` + +The actual command is just as follows: + +```bash +certbot nginx certonly --domain "example.com" --domain "www.example.com" --csr csr.pem +``` + +After a (long) delay, the client will output: + +1. Signed certificate: `0000_cert.pem` +2. Root and intermediate certificates: `0000_chain.pem` +3. Certificate + intermediates: `0001_chain.pem` +At this point, the CSR `csr.pem` can be deleted. + +If we are curious, we can inspect the certificates returned by the client with OpenSSL using the `x509` command: + +```bash +openssl x509 -in 0001_chain.pem -noout -text +``` + +Unfortunately, we will discover that as described above, Let's Encrypt signs our certificate with a SHA256 signature. (As well as being more secure, SHA512 outperforms SHA256 on modern 64-bit CPUs.) But our public key should still use ECDSA. + +These files are not ordinary, so we must move and edit them in a more informative way. + +On Debian Linux I like to create subdirectories for my domains by keeping my private key in `/home/USER_NAME/SSL/private/example.com/privkey.pem` and certificates: + +* `/home/USER_NAME/SSL/certs/example.com/cert.pem` +* `/home/USER_NAME/SSL/certs/example.com/chain.pem` +* `/home/USER_NAME/SSL/certs/example.com/fullchain.pem` + +# END + +If we've done everything right, inspecting the certificate with a web browser like Chrome will confirm that it's an EC certificate: + +![https://dev.to/benjaminblack/obtaining-an-elliptic-curve-dsa-certificate-with-lets-encrypt-51bc (Date: 08.04.2023)](/images/ecc-ssl/ecc-sll-key-chrome.png) + +Mozilla Observatory will also give us an A+ rating! + +![https://dev.to/benjaminblack/obtaining-an-elliptic-curve-dsa-certificate-with-lets-encrypt-51bc (Date: 08.04.2023)](/images/ecc-ssl/ecc-ssl-key-mozilla.png) + +In addition, we can see that a 384-bit ECC certificate was used as a result of the SSL Labs report. + +![SSL Labs Test Result](/images/ecc-ssl/ecc-ssl-key-ssllabs.png) + +NOTE: This article has benefited from the article of [Benjamin Black](https://dev.to/benjaminblack/obtaining-an-elliptic-curve-dsa-certificate-with-lets-encrypt-51bc) on the same subject. diff --git a/content/post/ecc-ssl-sertifikasi.md b/content/post/ecc-ssl-sertifikasi.md index c40e4716..cf81bc6c 100644 --- a/content/post/ecc-ssl-sertifikasi.md +++ b/content/post/ecc-ssl-sertifikasi.md @@ -1,220 +1,220 @@ ---- -title: "Linux Sunucuda ECC SSL Sertifikası Üretme" -date: 2022-03-20 -tags: ["linux", "ssl", "security", "ecc", "elliptic curve"] -author: "Wise" -draft: false ---- -# Giriş ve Özet - -Bugün sizlerle yönettiğiniz bir web sitesi veya uygulama sunucusu ile ziyaretçileriniz arasındaki trafiğin gizli/güvenilir ve doğrulanabilir olmasını sağlamak için SSL sertifikası üretmeyi öğreneceğiz. Ürettiğiniz sertifikayı nasıl ve hangi konfigürasyon ile deploy edeceğinizi önceki yazılarımda anlatmıştım. Bu yazıda ise az ekmek çok köfte denklemini nasıl kurabileceğimizi yani daha hızlı ve daha güvenli bir SSL sertifikası üretmeyi göstereceğim. Normalde Let's Encrypt'in ACME protokolüne aşina iseniz (yazının yazıldığı tarih itibariyle) RSA asimetrik anahtar yapısı ile 1024-4098 (çok zorlarsanız belki 8196) bitlik bir sertifika ürettirmeniz ve bunu görece olarak 90 gün kullanmanız mümkündür. Fakat bu kadar büyük bir anahtarın üretilmesi, ürettikten sonra TLS handshake sırasında kullanılması ve ziyaretçilerin kullandığı cihazlar ile uyumlu olması çoğu senaryoda sorun çıkarmaktadır. Örneğin 2048 bit yerine 4096 bit kullanıldığı zaman bazı denemelerimde 0.4-0.8 sn daha uzun handshake süreleri ile karşı karşıya kalıyorum. Sadece handshake in bu kadar uzaması sorun değilmiş gibi sunucuya da ekstra bir yük bindiriyor. Fakat 4096 bit RSA yerine 384 bit ECC sertifikası ürettiğiniz zaman çok daha hızlı bir sertifikaya sahip olduğunuz gibi aynı zamanda da 7680 bit RSA'ya (öyle bir boyut olsaydı) eşit bir güvenlik elde ediyorsunuz. - -Peki iyi güzel anlattın da bu işin aması nerede dediğinizi duyar gibiyim. Sizi üzeceğim fakat bu işin aması yok. Olmamasının sebebi ise işin arka plandaki matematikte saklı. Kısaca her iki sertifika üretim ve kullanımındaki ufak farklardan bahsedip, bunların nasıl ve neden büyük farklara neden olduğunu açıklayıp son kısımda da bonus olarak başlıkta yazmayan bir şeyden bahsedeceğim. (Sonuna kadar okumanız gerekecek bonus için :D) - -![https://www.globalsign.com/en/blog/elliptic-curve-cryptography (Erişim Tarihi: 08.04.2023)](/images/ecc-ssl/key-size-comparison.jpg) - -## ECC Sertifikasının üretim süreci - -Öncelikle (her zaman olduğu gibi) içinde bulunduğumuz Linux sürümünün paket yöneticisi ile son güncellemeleri konsol üzerinden yüklememiz gerekmektedir. - -```bash -Ubuntu için: sudo apt update && sudo apt upgrade -y - -Fedora için: sudo yum update -y - -Arch Linux için: sudo pacman -Syyu -``` - -Güncellemeler yüklendikten sonra ise sunucunuzdaki (Benim olayımda Ubuntu) nginx servisini (ki bu servis dışarıdan HTTP/HTTPS bağlantıları almanıza yarayan servistir) yapılandırmaya başlıyoruz. Öncelikle çok karıştırılması nedeniyle belirtmek gerekir ki apache, nginx ve litespeed servisleri aynı işi yapan farklı servislerdir. Ben yönetimi daha kolay ve topluluk desteği daha çok diye NGINX'i terchi ettim. - -## Özel anahtarı oluşturalım - -İlk olarak, OpenSSL ile özel anahtarı oluşturuyoruz. Kullanacağımız OpenSSL komutu `ecparam` (EC parametre manipülasyonu) ve konfigürasyon parametrelerini bu komuta geçirmek için: - -```bash -openssl ecparam -genkey -name secp384r1 -out privkey.pem -``` - -* `-genkey` seçeneği, OpenSSL'ye bir EC anahtarı oluşturmasını söyler. -* `-name` parametresi OpenSSL'ye hangi eğrinin kullanılacağını söyler. -* `-out` parametresi OpenSSL'ye çıktıyı bir dosyaya yazmasını söyler. - -OpenSSL'nin çıktısını varsayılan olarak PEM biçiminde yazdığını unutmayın. EC anahtarlarını işleyen `ec` komutuyla OpenSSL'nin doğru şeyi yaptığını kontrol edebiliriz: - -```bash -openssl ec -in privkey.pem -noout -text -``` - -* `-in` girdi dosyasıdır -* `-noout`, OpenSSL'ye anahtarı çıkarmamasını söyler, bu da privkey.pem'i stdout'a anlamsızca yazdırır. -* `-text`, OpenSSL'ye anahtar hakkındaki bilgileri düz metin biçiminde yazmasını söyler - -Her şey yolunda giderse ve anahtar doğru şekilde oluşturulduysa, OpenSSL aşağıdakine benzer bir şey gösterecektir: - -```text -read EC key -Private-Key: (384 bit) -priv: - [gizli] -pub: - [gizli] -ASN1 OID: secp384r1 -NIST CURVE: P-384 -``` - -Bu, anahtarın P-384 eğrisi ile oluşturulduğunu doğrular. Neden P-384 yerine P-512 kullanmıyoruz derseniz Let's Encrypt ekliptik eğrilerde 384 bitten daha yüksek olursa imzalamıyor ve Google Chrome gibi modern tarayıcılar 512 bitlik ekliptik eğrileri kullanan internet sitelerini geçersiz olarak işaretliyor. Kısa cevap bu. - -## Sertifika için OpenSSL yapılandırması oluşturalım - -Şimdi TLS sertifikası almak istediğimiz etki alanına özgü parametreleri içeren bir OpenSSL yapılandırma dosyası oluşturmalıyız. Bu örnekte, bir `openssl.cnf` dosyasına aşağıdaki konfigürasyonu gireceğiz: - -```text -[ req ] -prompt = no -encrypt_key = no -default_md = sha512 -distinguished_name = dname -req_extensions = reqext - -[ dname ] -CN = example.com -emailAddress = admin@example.com - -[ reqext ] -subjectAltName = DNS:example.com, DNS:www.example.com -``` - -Bu yapılandırma seçeneklerinin kısa bir açıklaması: - -Gerekli `[ req ]` bölümünde: - -* `prompt = no`, OpenSSL'ye yapılandırma dosyasından olabildiğince fazla yapılandırma almasını söyler -* `encrypt_key = no`, OpenSSL'ye özel anahtarı bir parola ile şifrelememesini söyler. (Şifreli özel anahtarlar Nginx tarafından desteklenir, ancak ben onları kullanmıyorum.) -* `default_md = sha512`, OpenSSL'ye CSR'yi SHA512 ile imzalamasını söyler. (Bildiğim kadarıyla, Let's Encrypt, imzaları için yalnızca SHA256'lı RSA'yı destekler, ancak bu, CSR'de daha güçlü şifreleme kullanamayacağımız anlamına gelmez.) -* `distinguished_name = dname`, OpenSSL'ye Ayırt Edici Ad yapılandırma seçenekleri için bir `[ dname ]` bölümü aramasını söyler. -* `req_extensions = reqext`, OpenSSL'ye, Konu Alternatif Adlarının (SAN'lar) yapılandırılmak istenen uzantılar için yapılandırma seçeneklerinde bir `[ reqext ]` bölümü aramasını söyler. - -Ayırt Edici Ad `[ dname ]` bölümünde: - -* `CN = example.com`, sertifikanın Ortak Adını belirtir. -* `emailAddress = admin@example.com` e-posta adresiniz belirgin olmalıdır. -İstenen Uzantılar `[ reqext ]` bölümünde, konuAltName, sertifika için SAN'ların listesini sağlar. (Chrome, v58'den itibaren, Ortak Adın SAN'lar listesine dahil edilmesini gerektirir). - -Let's Encrypt v2, joker alan adlarını destekler, bu nedenle bu örnekte, apeks dışındaki ana bilgisayarlar için tek düzeyli bir joker karakter kullanabilirsiniz (*.example.com). - -## Sertifika İmzalama İsteği Oluşturalım - -İstemci tarafındaki son adım, OpenSSL kullanarak Sertifika İmzalama Talebi oluşturmaktır, ardından bunu imzalamak için Let's Encrypt'e ileteceğiz ve imzalı sertifikayı geri alacağız. - -Bir CSR oluşturmak için gereken OpenSSL komutu `req` 'dir. - -```bash -openssl req -new -config openssl.cnf -key privkey.pem -out csr.pem -``` - -* `-new`, OpenSSL'ye bir CSR oluşturduğumuzu söyler (ve mevcut bir CSR'yi incelemeyiz) -* `-config` openssl.cnf, yukarıda oluşturduğumuz yapılandırma dosyasını belirtir -* `-key privkey.pem`, yukarıda oluşturduğumuz özel anahtarı belirtir -* `-out csr.pem` OpenSSL'ye CSR'yi bir çıktı dosyasına yazmasını söyler (stdout yerine) - -CSR'yi doğru şekilde oluşturduğumuzu doğrulayabiliriz: - -```bash -openssl req -in csr.pem -noout -text -verify -``` - -* `-verify` OpenSSL'nin CSR'deki imzayı doğrulamasını ister - -Bu, çıktıda beklenen şu sonuçları üretmelidir: - -```text -verify OK -Certificate Request: - Data: - Version: 1 (0x0) - Subject: CN = example.com, emailAddress = admin@example.com - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (384 bit) - pub: - [gizli] - ASN1 OID: secp384r1 - NIST CURVE: P-384 - Attributes: - Requested Extensions: - X509v3 Subject Alternative Name: - DNS:example.com, DNS:www.example.com - Signature Algorithm: ecdsa-with-SHA512 - [gizli] -``` - -## Let's Encrypt'ten sertifikamızı imzalamasını isteyin - -Son adım, CSR'yi bir ACME istemcisiyle Let's Encrypt'e imzalaması için göndermektir, bu iş için `certbot` en yaygın istemcidir. - -`Certbot` istemcisine iletilen komut satırı seçenekleri, kurulumumuza, alan adımızın kayıtlı olduğu kişiye vb. bağlı olarak değişir. Genellikle `certonly` komutunu kullanmamız gerekir ve asterisks (*) kullandıysanız certbot DNS eklentilerinden birini kullanmanız gerekir. - -Örneğin, `example.com` alan adı Cloudflare'de kayıtlıysa, son derece uygun olan ve sürece manuel müdahale gerektirmeyen doğrulamayı işlemek için ilgili eklentiyi kullanabiliriz. (Cloudflare eklentisini gizli token bilgileriyle yapılandırmak bu makalenin kapsamı dışındadır.) - -Her şeyin yolunda olduğundan emin olmak için önce `--dry-run` ile düzgün sonuç alınacağından emin olunması genellikle tavsiye edilir. - -```bash -certbot nginx certonly --dry-run --domain "example.com" --domain "www.example.com" --csr csr.pem -``` - -* Hatalı işlemeleri önlemek için karakterlerin etrafında tırnak işaretleri gereklidir ve genel olarak bunlar iyi bir fikirdir. -* `--csr csr.pem` certbot'a zaten bir sertifikamız olduğunu ve bizim için imzalaması için Let's Encrypt'e ihtiyacımız olduğunu söyler. - -Certbot istemcisi, komut satırında istenen alan adları listesinin sertifikada listelenen alan adlarıyla eşleşip eşleşmediğini kontrol edecek ve alan adının bize ait olduğunu doğrulamak için Certbot NGINX eklentisini kullanacak ve herhangi bir sorun olup olmadığını bize bildirecektir. - -Hiçbir şey yanlış değilse, size şunu söyleyecektir: - -```text -IMPORTANT NOTES: - - The dry run was successful. -``` - -Gerçek komut hemen aşağıdaki gibidir: - -```bash -certbot nginx certonly --domain "example.com" --domain "www.example.com" --csr csr.pem -``` - -(Uzun) bir gecikmeden sonra, istemci çıktı olarak şunları üretecektir: - -1. İmzalı sertifika: `0000_cert.pem` -2. Kök ve ara sertifikalar: `0000_chain.pem` -3. Sertifika + ara ürünler: `0001_chain.pem` -Bu noktada, CSR `csr.pem` silinebilir. - -Merak ediyorsak, `x509` komutunu kullanarak istemci tarafından OpenSSL ile döndürülen sertifikaları inceleyebiliriz: - -```bash -openssl x509 -in 0001_chain.pem -noout -text -``` - -Ne yazık ki, yukarıda açıklandığı gibi Let's Encrypt'in sertifikamızı bir SHA256 imzasıyla imzaladığını keşfedeceğiz. (Daha güvenli olmasının yanı sıra, SHA512, modern 64-bit CPU'larda SHA256'dan daha iyi performans gösterir.) Ancak açık anahtarımız yine de ECDSA kullanmalıdır. - -Bu dosyalar sıradan değildir, bu yüzden onları daha bilgilendirici bir şekilde taşımalı ve düzenlemeliyiz. - -Debian Linux'ta, özel anahtarımı `/home/KULLANICI_ADI/SSL/private/example.com/privkey.pem` içinde tutarak etki alanlarım için alt dizinler oluşturmayı seviyorum ve sertifikalar: - -* `/home/KULLANICI_ADI/SSL/certs/example.com/cert.pem` -* `/home/KULLANICI_ADI/SSL/certs/example.com/chain.pem` -* `/home/KULLANICI_ADI/SSL/certs/example.com/fullchain.pem` - -# SON - -Her şeyi doğru yaptıysak, sertifikayı Chrome gibi bir web tarayıcısı ile incelediğimizde, bunun bir EC sertifikası olduğunu onaylayacaktır: - -![https://dev.to/benjaminblack/obtaining-an-elliptic-curve-dsa-certificate-with-lets-encrypt-51bc (Erişim Tarihi: 08.04.2023)](/images/ecc-ssl/ecc-sll-key-chrome.png) - -Mozilla Gözlemevi de bize A+ notu verecek! - -![https://dev.to/benjaminblack/obtaining-an-elliptic-curve-dsa-certificate-with-lets-encrypt-51bc (Erişim Tarihi: 08.04.2023)](/images/ecc-ssl/ecc-ssl-key-mozilla.png) - -Ayrıca SSL Labs'ın rapor sonucunda 384 Bitlik bir ECC sertifikası'nın kullanıldığını görebiliyoruz. - -![SSL Labs Test Sonucu](/images/ecc-ssl/ecc-ssl-key-ssllabs.png) - -NOT: Bu yazıda [Benjamin Black](https://dev.to/benjaminblack/obtaining-an-elliptic-curve-dsa-certificate-with-lets-encrypt-51bc)'in aynı konulu yazısından faydalanılmıştır. +--- +title: "Linux Sunucuda ECC SSL Sertifikası Üretme" +date: 2022-03-20 +tags: ["linux", "ssl", "security", "ecc", "elliptic curve"] +author: "Wise" +draft: false +--- +# Giriş ve Özet + +Bugün sizlerle yönettiğiniz bir web sitesi veya uygulama sunucusu ile ziyaretçileriniz arasındaki trafiğin gizli/güvenilir ve doğrulanabilir olmasını sağlamak için SSL sertifikası üretmeyi öğreneceğiz. Ürettiğiniz sertifikayı nasıl ve hangi konfigürasyon ile deploy edeceğinizi önceki yazılarımda anlatmıştım. Bu yazıda ise az ekmek çok köfte denklemini nasıl kurabileceğimizi yani daha hızlı ve daha güvenli bir SSL sertifikası üretmeyi göstereceğim. Normalde Let's Encrypt'in ACME protokolüne aşina iseniz (yazının yazıldığı tarih itibariyle) RSA asimetrik anahtar yapısı ile 1024-4098 (çok zorlarsanız belki 8196) bitlik bir sertifika ürettirmeniz ve bunu görece olarak 90 gün kullanmanız mümkündür. Fakat bu kadar büyük bir anahtarın üretilmesi, ürettikten sonra TLS handshake sırasında kullanılması ve ziyaretçilerin kullandığı cihazlar ile uyumlu olması çoğu senaryoda sorun çıkarmaktadır. Örneğin 2048 bit yerine 4096 bit kullanıldığı zaman bazı denemelerimde 0.4-0.8 sn daha uzun handshake süreleri ile karşı karşıya kalıyorum. Sadece handshake in bu kadar uzaması sorun değilmiş gibi sunucuya da ekstra bir yük bindiriyor. Fakat 4096 bit RSA yerine 384 bit ECC sertifikası ürettiğiniz zaman çok daha hızlı bir sertifikaya sahip olduğunuz gibi aynı zamanda da 7680 bit RSA'ya (öyle bir boyut olsaydı) eşit bir güvenlik elde ediyorsunuz. + +Peki iyi güzel anlattın da bu işin aması nerede dediğinizi duyar gibiyim. Sizi üzeceğim fakat bu işin aması yok. Olmamasının sebebi ise işin arka plandaki matematikte saklı. Kısaca her iki sertifika üretim ve kullanımındaki ufak farklardan bahsedip, bunların nasıl ve neden büyük farklara neden olduğunu açıklayıp son kısımda da bonus olarak başlıkta yazmayan bir şeyden bahsedeceğim. (Sonuna kadar okumanız gerekecek bonus için :D) + +![https://www.globalsign.com/en/blog/elliptic-curve-cryptography (Erişim Tarihi: 08.04.2023)](/images/ecc-ssl/key-size-comparison.jpg) + +## ECC Sertifikasının üretim süreci + +Öncelikle (her zaman olduğu gibi) içinde bulunduğumuz Linux sürümünün paket yöneticisi ile son güncellemeleri konsol üzerinden yüklememiz gerekmektedir. + +```bash +Ubuntu için: sudo apt update && sudo apt upgrade -y + +Fedora için: sudo yum update -y + +Arch Linux için: sudo pacman -Syyu +``` + +Güncellemeler yüklendikten sonra ise sunucunuzdaki (Benim olayımda Ubuntu) nginx servisini (ki bu servis dışarıdan HTTP/HTTPS bağlantıları almanıza yarayan servistir) yapılandırmaya başlıyoruz. Öncelikle çok karıştırılması nedeniyle belirtmek gerekir ki apache, nginx ve litespeed servisleri aynı işi yapan farklı servislerdir. Ben yönetimi daha kolay ve topluluk desteği daha çok diye NGINX'i terchi ettim. + +## Özel anahtarı oluşturalım + +İlk olarak, OpenSSL ile özel anahtarı oluşturuyoruz. Kullanacağımız OpenSSL komutu `ecparam` (EC parametre manipülasyonu) ve konfigürasyon parametrelerini bu komuta geçirmek için: + +```bash +openssl ecparam -genkey -name secp384r1 -out privkey.pem +``` + +* `-genkey` seçeneği, OpenSSL'ye bir EC anahtarı oluşturmasını söyler. +* `-name` parametresi OpenSSL'ye hangi eğrinin kullanılacağını söyler. +* `-out` parametresi OpenSSL'ye çıktıyı bir dosyaya yazmasını söyler. + +OpenSSL'nin çıktısını varsayılan olarak PEM biçiminde yazdığını unutmayın. EC anahtarlarını işleyen `ec` komutuyla OpenSSL'nin doğru şeyi yaptığını kontrol edebiliriz: + +```bash +openssl ec -in privkey.pem -noout -text +``` + +* `-in` girdi dosyasıdır +* `-noout`, OpenSSL'ye anahtarı çıkarmamasını söyler, bu da privkey.pem'i stdout'a anlamsızca yazdırır. +* `-text`, OpenSSL'ye anahtar hakkındaki bilgileri düz metin biçiminde yazmasını söyler + +Her şey yolunda giderse ve anahtar doğru şekilde oluşturulduysa, OpenSSL aşağıdakine benzer bir şey gösterecektir: + +```text +read EC key +Private-Key: (384 bit) +priv: + [gizli] +pub: + [gizli] +ASN1 OID: secp384r1 +NIST CURVE: P-384 +``` + +Bu, anahtarın P-384 eğrisi ile oluşturulduğunu doğrular. Neden P-384 yerine P-512 kullanmıyoruz derseniz Let's Encrypt ekliptik eğrilerde 384 bitten daha yüksek olursa imzalamıyor ve Google Chrome gibi modern tarayıcılar 512 bitlik ekliptik eğrileri kullanan internet sitelerini geçersiz olarak işaretliyor. Kısa cevap bu. + +## Sertifika için OpenSSL yapılandırması oluşturalım + +Şimdi TLS sertifikası almak istediğimiz etki alanına özgü parametreleri içeren bir OpenSSL yapılandırma dosyası oluşturmalıyız. Bu örnekte, bir `openssl.cnf` dosyasına aşağıdaki konfigürasyonu gireceğiz: + +```text +[ req ] +prompt = no +encrypt_key = no +default_md = sha512 +distinguished_name = dname +req_extensions = reqext + +[ dname ] +CN = example.com +emailAddress = admin@example.com + +[ reqext ] +subjectAltName = DNS:example.com, DNS:www.example.com +``` + +Bu yapılandırma seçeneklerinin kısa bir açıklaması: + +Gerekli `[ req ]` bölümünde: + +* `prompt = no`, OpenSSL'ye yapılandırma dosyasından olabildiğince fazla yapılandırma almasını söyler +* `encrypt_key = no`, OpenSSL'ye özel anahtarı bir parola ile şifrelememesini söyler. (Şifreli özel anahtarlar Nginx tarafından desteklenir, ancak ben onları kullanmıyorum.) +* `default_md = sha512`, OpenSSL'ye CSR'yi SHA512 ile imzalamasını söyler. (Bildiğim kadarıyla, Let's Encrypt, imzaları için yalnızca SHA256'lı RSA'yı destekler, ancak bu, CSR'de daha güçlü şifreleme kullanamayacağımız anlamına gelmez.) +* `distinguished_name = dname`, OpenSSL'ye Ayırt Edici Ad yapılandırma seçenekleri için bir `[ dname ]` bölümü aramasını söyler. +* `req_extensions = reqext`, OpenSSL'ye, Konu Alternatif Adlarının (SAN'lar) yapılandırılmak istenen uzantılar için yapılandırma seçeneklerinde bir `[ reqext ]` bölümü aramasını söyler. + +Ayırt Edici Ad `[ dname ]` bölümünde: + +* `CN = example.com`, sertifikanın Ortak Adını belirtir. +* `emailAddress = admin@example.com` e-posta adresiniz belirgin olmalıdır. +İstenen Uzantılar `[ reqext ]` bölümünde, konuAltName, sertifika için SAN'ların listesini sağlar. (Chrome, v58'den itibaren, Ortak Adın SAN'lar listesine dahil edilmesini gerektirir). + +Let's Encrypt v2, joker alan adlarını destekler, bu nedenle bu örnekte, apeks dışındaki ana bilgisayarlar için tek düzeyli bir joker karakter kullanabilirsiniz (*.example.com). + +## Sertifika İmzalama İsteği Oluşturalım + +İstemci tarafındaki son adım, OpenSSL kullanarak Sertifika İmzalama Talebi oluşturmaktır, ardından bunu imzalamak için Let's Encrypt'e ileteceğiz ve imzalı sertifikayı geri alacağız. + +Bir CSR oluşturmak için gereken OpenSSL komutu `req` 'dir. + +```bash +openssl req -new -config openssl.cnf -key privkey.pem -out csr.pem +``` + +* `-new`, OpenSSL'ye bir CSR oluşturduğumuzu söyler (ve mevcut bir CSR'yi incelemeyiz) +* `-config` openssl.cnf, yukarıda oluşturduğumuz yapılandırma dosyasını belirtir +* `-key privkey.pem`, yukarıda oluşturduğumuz özel anahtarı belirtir +* `-out csr.pem` OpenSSL'ye CSR'yi bir çıktı dosyasına yazmasını söyler (stdout yerine) + +CSR'yi doğru şekilde oluşturduğumuzu doğrulayabiliriz: + +```bash +openssl req -in csr.pem -noout -text -verify +``` + +* `-verify` OpenSSL'nin CSR'deki imzayı doğrulamasını ister + +Bu, çıktıda beklenen şu sonuçları üretmelidir: + +```text +verify OK +Certificate Request: + Data: + Version: 1 (0x0) + Subject: CN = example.com, emailAddress = admin@example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + [gizli] + ASN1 OID: secp384r1 + NIST CURVE: P-384 + Attributes: + Requested Extensions: + X509v3 Subject Alternative Name: + DNS:example.com, DNS:www.example.com + Signature Algorithm: ecdsa-with-SHA512 + [gizli] +``` + +## Let's Encrypt'ten sertifikamızı imzalamasını isteyin + +Son adım, CSR'yi bir ACME istemcisiyle Let's Encrypt'e imzalaması için göndermektir, bu iş için `certbot` en yaygın istemcidir. + +`Certbot` istemcisine iletilen komut satırı seçenekleri, kurulumumuza, alan adımızın kayıtlı olduğu kişiye vb. bağlı olarak değişir. Genellikle `certonly` komutunu kullanmamız gerekir ve asterisks (*) kullandıysanız certbot DNS eklentilerinden birini kullanmanız gerekir. + +Örneğin, `example.com` alan adı Cloudflare'de kayıtlıysa, son derece uygun olan ve sürece manuel müdahale gerektirmeyen doğrulamayı işlemek için ilgili eklentiyi kullanabiliriz. (Cloudflare eklentisini gizli token bilgileriyle yapılandırmak bu makalenin kapsamı dışındadır.) + +Her şeyin yolunda olduğundan emin olmak için önce `--dry-run` ile düzgün sonuç alınacağından emin olunması genellikle tavsiye edilir. + +```bash +certbot nginx certonly --dry-run --domain "example.com" --domain "www.example.com" --csr csr.pem +``` + +* Hatalı işlemeleri önlemek için karakterlerin etrafında tırnak işaretleri gereklidir ve genel olarak bunlar iyi bir fikirdir. +* `--csr csr.pem` certbot'a zaten bir sertifikamız olduğunu ve bizim için imzalaması için Let's Encrypt'e ihtiyacımız olduğunu söyler. + +Certbot istemcisi, komut satırında istenen alan adları listesinin sertifikada listelenen alan adlarıyla eşleşip eşleşmediğini kontrol edecek ve alan adının bize ait olduğunu doğrulamak için Certbot NGINX eklentisini kullanacak ve herhangi bir sorun olup olmadığını bize bildirecektir. + +Hiçbir şey yanlış değilse, size şunu söyleyecektir: + +```text +IMPORTANT NOTES: + - The dry run was successful. +``` + +Gerçek komut hemen aşağıdaki gibidir: + +```bash +certbot nginx certonly --domain "example.com" --domain "www.example.com" --csr csr.pem +``` + +(Uzun) bir gecikmeden sonra, istemci çıktı olarak şunları üretecektir: + +1. İmzalı sertifika: `0000_cert.pem` +2. Kök ve ara sertifikalar: `0000_chain.pem` +3. Sertifika + ara ürünler: `0001_chain.pem` +Bu noktada, CSR `csr.pem` silinebilir. + +Merak ediyorsak, `x509` komutunu kullanarak istemci tarafından OpenSSL ile döndürülen sertifikaları inceleyebiliriz: + +```bash +openssl x509 -in 0001_chain.pem -noout -text +``` + +Ne yazık ki, yukarıda açıklandığı gibi Let's Encrypt'in sertifikamızı bir SHA256 imzasıyla imzaladığını keşfedeceğiz. (Daha güvenli olmasının yanı sıra, SHA512, modern 64-bit CPU'larda SHA256'dan daha iyi performans gösterir.) Ancak açık anahtarımız yine de ECDSA kullanmalıdır. + +Bu dosyalar sıradan değildir, bu yüzden onları daha bilgilendirici bir şekilde taşımalı ve düzenlemeliyiz. + +Debian Linux'ta, özel anahtarımı `/home/KULLANICI_ADI/SSL/private/example.com/privkey.pem` içinde tutarak etki alanlarım için alt dizinler oluşturmayı seviyorum ve sertifikalar: + +* `/home/KULLANICI_ADI/SSL/certs/example.com/cert.pem` +* `/home/KULLANICI_ADI/SSL/certs/example.com/chain.pem` +* `/home/KULLANICI_ADI/SSL/certs/example.com/fullchain.pem` + +# SON + +Her şeyi doğru yaptıysak, sertifikayı Chrome gibi bir web tarayıcısı ile incelediğimizde, bunun bir EC sertifikası olduğunu onaylayacaktır: + +![https://dev.to/benjaminblack/obtaining-an-elliptic-curve-dsa-certificate-with-lets-encrypt-51bc (Erişim Tarihi: 08.04.2023)](/images/ecc-ssl/ecc-sll-key-chrome.png) + +Mozilla Gözlemevi de bize A+ notu verecek! + +![https://dev.to/benjaminblack/obtaining-an-elliptic-curve-dsa-certificate-with-lets-encrypt-51bc (Erişim Tarihi: 08.04.2023)](/images/ecc-ssl/ecc-ssl-key-mozilla.png) + +Ayrıca SSL Labs'ın rapor sonucunda 384 Bitlik bir ECC sertifikası'nın kullanıldığını görebiliyoruz. + +![SSL Labs Test Sonucu](/images/ecc-ssl/ecc-ssl-key-ssllabs.png) + +NOT: Bu yazıda [Benjamin Black](https://dev.to/benjaminblack/obtaining-an-elliptic-curve-dsa-certificate-with-lets-encrypt-51bc)'in aynı konulu yazısından faydalanılmıştır. diff --git a/content/post/fotograf-compress-magick.md b/content/post/fotograf-compress-magick.md new file mode 100644 index 00000000..c23dc712 --- /dev/null +++ b/content/post/fotograf-compress-magick.md @@ -0,0 +1,733 @@ +--- +title: "Fotoğraf sıkıştırma yöntemleri rehberi" +date: 2024-06-16 +tags: ["imagemagick", "webp", "cwebp", "avif", "heic", "heif", "magick", "avifenc"] +author: "Wise" +draft: false +--- + +# Giriş + +||| +|:---:|:---:| +![1](/images/fotograf-compress-magick/giris1.png) | ![2](/images/fotograf-compress-magick/giris2.png) + +Günümüzde yüksek kaliteli görüntüler satın aldığımız fotoğraf makineleri veya en basitinden cebimizdeki telefonlar aracılığı ile çok kolay ulaşılabilir hale geldi. Mesela son 4-5 sene içerisinde aldığımız bir telefon ile yüksek çözünürlüklü (50-100MP) fotoğraf çekebiliyor veya yüksek çözünürlüklü olmasa dahi RAW formatında daha fazla veri içeren fotoğraflar elde edebiliyoruz. Yani eskiden dert yakındığımız birçok konu (çözünürlük, kalite vb.) günümüzdeki teknolojiler tarafından sorun olmaktan çıkarıldı. Fakat bununla birlikte beraberlerinde yeni sorunları da getirmeyi ihmal etmediler. Bunun en bilinen örneği ise yüksek dosya boyutları nedeniyle kısa sürede dosyaları depolayamaz hale gelmek. Örnek vermek gerekirse eğer yakın zamanda bir arkadaşımın yaşadığı bir durumdan bahsetmek isterim. Kendisi bir iPhone kullanıcısı olarak telefonunu aldığı günden beridir aralıksız her etkinliğimizde grup fotoğraflarımızı çeker ve kendisi de bunun haricinde fotoğraf çekmeyi sever. Sonuç olarak kısa bir süre içerisinde telefonunun tüm hafızasını (çoğunluğu fotoğraf olmak üzere) doldurdu. Çektiği fotoğrafları çok sevdiğinden ve hiçbirini silmek istemediğinden dolayı bana bir çözüm bulmam için geldi. Ben de bu süreçte kendisine önerdiğim çözümleri ve bu süreçte yaptığım açıklamaları bir rehber haline getirip size sunmak istedim. + +Bu yazıda, modern görüntü sıkıştırma araçlarından ikisi olan avifenc ve cwebp'yi ele alacağız. Özellikle web geliştiricileri (benim tanışma şeklimde de böyle oldu) ve tasarımcılar için değerli olan bu araçlar, AVIF ve WebP formatlarında yüksek verimli sıkıştırma sunar. Her iki araç da ücretsiz ve açık kaynaklı olup, geniş bir kullanıcı topluluğu tarafından desteklenmektedir. WebP formatı Google tarafından geliştirilmekte olup Open Media Alliance tarafından geliştirilmektedir. + +# Fotoğraf Sıkıştırma Teknikleri: Detaylı Bir İnceleme + +BU yazıda fotoğraf sıkıştırma tekniklerinin temellerini ve bu tekniklerin nasıl çalıştığını inceleyeceğiz. Öncelikle kayıplı ve kayıpsız sıkıştırma arasındaki farkları, ardından her iki tür sıkıştırmada kullanılan yöntemleri ele alacağız. Ardında da avifenc ve cwebp araçlarının nasıl kullanılacağını, avantajlarını ve en iyi uygulama yöntemlerini inceleyeceğiz. Bu kısım biraz teknik ilerleyecek olup yazının sonraki kısmında ise her zaman olduğu gibi bu sürecin başkaca bir yazılım ile hızlı ve çok teknik detaya girmeden uygulanmasından da bahsedeceğim. Bu kısmı isterseniz atlayıp direkt yandan "Imagemagick Yazılımı" ile ilgili başlığa tıklayabilirsiniz. + +## Kayıplı ve Kayıpsız Sıkıştırma Arasındaki Fark + +### Kayıpsız Sıkıştırma + +Kayıpsız sıkıştırma, görüntü kalitesini hiç değiştirmeden veri boyutunu azaltmayı amaçlar. Bu yöntemde, orijinal veri sıkıştırıldıktan sonra tam olarak geri dönüştürülebilir. Kayıpsız sıkıştırma özellikle yüksek kaliteden az da olsa ödün vermek istemeyen aynı zamanda da mümkün olan bir miktarda yer kazanmayı isteyen kişiler için uygundur. Ayrıca kayıpsız sıkıştırma genellikle pikseller arası korelasyonun düşük olduğu şekil gibi görüntülerde kullanıma daha müsaittir. + +### Kayıplı Sıkıştırma + +Kayıplı sıkıştırma dosya boyutunu daha fazla küçültmek için bir miktar veri kaybına izin verir. Bu yöntemde sıkıştırma sonrası görüntü orijinaline çok benzerdir fakat birebir aynı değildir. Mesela renk uzayı, bazı renklerin kodlanması ve bir takım detaylarda değişmeler/azalmalar olması muhtemeldir. Kayıplı sıkıştırma genel olarak webde paylaşılacak görüntülerde, sosyal medya ve genel fotoğraf depolama çözümleri için yaygın olarak kullanılır. Kayıplı sıkıştırma ile dosya boyutunu önemli ölçüde düşürme karmaşık ve yüksek korelasyona sahip görüntülerde daha çok kullanılmaktadır. + +## Kayıpsız Sıkıştırmada Kullanılan Yöntemler + +### Run-Length Encoding (RLE) + +Run-Length Encoding, veri dizilerinde tekrarlanan öğeleri sıkıştırmak için kullanılır. Örneğin, bir görüntüde ardışık olarak gelen aynı renkteki pikseller, tek bir veri değeri ve bu değerin tekrar sayısı ile temsil edilir. Bu yöntem, uzun tekrarlanan piksellerin olduğu görüntülerde oldukça etkilidir. Sıralı renk tekrarlarının olduğu homojen renk dağılımlı görüntülerde RLE algoritması başarılı bir sıkıştırma yapabilmektedir. Diğer taraftan tekrarların az olduğu veya renklerin homojen bir dağılım göstermediği görüntülerde algoritmanın başarısı düşük kalabilmektedir. Örneğin aynı meyve/sebzelerden oluşan bir tabağın çekilen fotoğrafı bu yöntem için oldukça uygun bir seçimdir. + +### Huffman Coding + +Zamanında MIT'de öğrenci olan David Huffman tarafından hocasının verdiği bir ödev üzerine geliştirilmiştir. Yaygın olarak kullanılan sıkıştırma yöntemlerinde son işlem olarak kullanılır ve muhtemelen sıkıştırma algoritmalarında en yaygın olarak kullanılan bileşendir. Huffman kodlamanın temel amacı, verideki frekanslarına göre veri parçalarının her birine değişken uzunluklarda kodlar atayarak verinin toplam kod uzunluğunu en aza indirmektir. Yüksek frekanslı parçalara daha kısa kodlar, düşük frekanslı parçalara ise nispeten daha uzun kodlar atanarak dosya boyutu düşürülmüş olur. Örneğin 0001 olarak kodlanan bir parçanın karşımıza çıkma olasılığı (mesela) 00000001 olarak kodlanmış bir parçadan daha yüksektir. Buna göre ilk parçaya daha kısa bir kod atanırken diğer parçaya daha uzun bir kod atanacaktır. + +### LZW (Lempel-Ziv-Welch) + +LZW, veri dizilerindeki tekrarları tespit eder ve bu tekrarları sıkıştırılmış bir kod olarak saklar. Daha kısa kod yerine geçtiği dizeden daha az yer kaplar ve daha küçük bir dosya elde edilir. Girdi verilerinde uzun veya tekrarlayan kelimelerin sayısı arttıkça algoritmanın verimliliği de artar. Grafik dosya formatları (GIF) ve çeşitli arşiv formatları (ZIP) gibi birçok uygulamada kullanılır. Bunu LZ77/78 olarak biliyor veya duymuş da olabilirsiniz. Daha önce 7zip kullanmış iseniz bununla karşılaşmış olmanız pek muhtemel. + +### Flate/Deflate + +Flate/Deflate Phil Katz tarafından 90’lı yılların ortalarında geliştirilmiş kayıpsız veri sıkıştırma formatıdır. Huffman Kodlaması ve LZ77 algoritmasının bir bileşimidir. PNG kayıpsız görüntü sıkıştırma standardı Deflate algoritmasını kullanmaktadır. Sıkıştırılacak olan veri birbirini takip eden bloklar kümesi olarak düşünülür. Her blok LZ77 algoritması ve Huffman kodlamasının birlikte kullanılması ile sıkıştırılır. Her blok için oluşturulan Huffman ağacı bir önceki ve bir sonraki bloktan bağımsızdır. Sıkıştırılabilen blokların büyüklüğü değişkendir. Deflate algoritması Huffman ağacının etkili kodlama yapamayacak kadar büyüdüğünü gördüğünde, yeni bir Huffman ağacı oluşturmak için o bloğu sonlandırarak yeni bir blok başlatır. Böylece daha verimli bir sıkıştırma yapmayı amaçlar. + +### Color Quantization (Kısmen) + +Renk sayısının veya derinliğinin azaltılmasıyla ya da renk uzayında yapılan değişikliklerle sıkıştırma sağlanır. Örneğin, bir görüntüde kullanılan renk sayısını 256 ile sınırlayarak dosya boyutu düşürülebilir. Bu teknik, genellikle GIF formatında kullanılır. Kayıpsız sıkıştırma yöntemlerinin sonuna bunu da eklememin sebebi kısmi bir bakış açısına göre kayıpsız sayılabileceği yönünde. Burada K-Means denilen bir terim devreye giriyor ve düzgün uyarlandığında tek başına dosya boyutunu 100'de 1 oranına kadar (aşırı ve bence gerçek dışı bir oran) düşürebildiğinden bahsediliyor. + +## Kayıplı Sıkıştırmada Kullanılan Yöntemler + +### Transform Kodlama (DCT) + +Transform kodlama, görüntü verilerini frekans bileşenlerine dönüştürerek sıkıştırma sağlar. JPEG sıkıştırmasında yaygın olarak kullanılan Discrete Cosine Transform (DCT) buna bir örnektir.Sıkıştırma aşamalarında ilk olarak görsele RGB-YUV renk uzayı dönüşümü uygulanır. Sonrasında görsel 8×8 bloklara ayrılır ve her bloğa DCT uygulanır. DCT uygulanmış blok, 1-100 arasında, 1 en düşük kalite ve 100 en yüksek kalite olmak üzere kullanıcı tarafından seçilebilen bir kalite parametresine karşılık gelen kuantizasyon matrisi kullanılarak kuantalanır. + +Bununla ilgili Computerphile videosu: https://www.youtube.com/watch?v=Q2aEzeMDHMA + +### Chroma Subsampling + +Chroma subsampling, insan gözünün renk değişikliklerine duyarlılığının düşük olmasını kullanarak renk bilgilerini azaltır. YCbCr renk modelinde renk bileşenlerinin (Chroma) yatay ve/veya dikey çözünürlüğünü düşürerek sıkıştırma yapar. İlerleyen adımlarda size göstereceğim örnek görsellerden .yuv uzantılı olan 4:2:0 olarak sample edilmişken .y4m ve .ycbcr 4:4:4 olarak kabul edilebilir. Bu da herhangi başka bir işlem yapmandan 4:4:4 --> 4:2:0 veya 4:1:1 dönüşümünde %50 4:4:4: --> 4:2:2 dönüşümünde %33 civarında bir dosya boyut azalması sağlıyor. Bu bildiğimiz anlamda bir sıkıştırma yapmadan elde edilen ve gerçekten çok yüksek bir oran olan bir kazanç. + +### Fraktal Sıkıştırma + +Fraktal sıkıştırma, görüntüdeki tekrarlayan desenleri matematiksel fraktal algoritmalarla sıkıştırır. Fraktal sıkıştırmanın tekrarlanan fonksiyonlar ile gerçeklenebileceği fikri ilk defa Michael Barnsley ve Alan Sloan tarafından ortaya atılmıştır. Fraktal tekniğinin en önemli avantajı, açma işleminin basit ve hızlı olmasıdır. Fakat sıkıştırma işlemi, açmanın tam tersine çok karmaşıktır. Bir resimdeki tekrar eden fraktalları bulmak milyonlarca, milyarlarca karşılaştırma işleminin yapılmasını gerektirebilir. Sıkıştırma işleminin çok zaman alması nedeniyle fraktal tekniği henüz yeterince yaygınlaşamamıştır. Bu yöntem, yüksek sıkıştırma oranları sağlar ancak bahsedildiği gibi hesaplama süreci genellikle daha uzundur. + +## Kayıpsız (veya kısmen kayıpsız) Görüntü Çözümleri + +### YCBCR + +YCBCR, bir renk kodlama şemasıdır ve tek başına bir görüntü formatı değildir. Genellikle dijital video ve fotoğrafçılıkta kullanılır. Kayıpsız veya kayıplı sıkıştırma ile kullanılabilir. JPEG gibi kayıplı formatlarda da (çok mantıklı olmasa da) YCBCR renk alanını kullanabilir. + +### YUV + +YUV (ycbcr de olduğu gibi) bir renk alanı ve aynı zamanda video verilerini saklamak için kullanılan bir format olabilir. Veriler sıkıştırılmamış veya kayıplı/kayıpsız sıkıştırma ile saklanabilir. YUV dosyalarının kayıpsız olup olmadığı kullanılan sıkıştırma yöntemine bağlıdır. Bugün biz sıkıştırılmamış olan halinden faydalanacağız. + +### Y4M + +Y4M, YUV4MPEG2 video formatının bir dosya uzantısıdır. Bu format sıkıştırılmamış YUV video verilerini içerir ve bundan dolayı kayıpsızdır. Y4M genellikle video/fotoğraf işleme ve düzenleme yazılımlarında ara format olarak kullanılır. Biz de bugün bu amaçla kullanacağız. + +### PPM + +PPM sıkıştırılmamış (dolayısıyla kayıpsız) bir görüntü formatıdır. PPM'de her pikselin kırmızı, yeşil ve mavi (RGB) bileşenlerini ASCII veya ikili formda saklanır. Kanaviçe yapar gibi düşünebilirsiniz. Sıkıştırılmamış olduğu için dosya boyutları oldukça büyük olabilir. Konumuzda kullanılacak ana giriş formatı bu olacaktır. Diğer üç format ise ara format veya kontrol formatı olarak kullanılacaktır. + +## Kayıplı Sıkıştırma Kullanan Görüntü Formatları + +### WebP + +Google tarafından geliştirilen WebP, hem kayıplı hem de kayıpsız sıkıştırma destekleyen modern bir görüntü formatıdır. JPEG'e kıyasla daha yüksek sıkıştırma oranları ve daha düşük dosya boyutları sunar. Modern tarayıcıların büyük kısmı tarafından hali hazırda kullanılan ve ek bir bileşene gerek bırakmayan bir formattır. + +### HEIC (High Efficiency Image Coding) + +HEIC/HEIF özellikle Apple cihazlarda yaygın olarak kullanılan bir görüntü formatıdır. Yüksek verimlilikte sıkıştırma sağlamak için HEVC (High Efficiency Video Coding) teknolojisini kullanır. Fakat Apple burada farklı bir bakış açısı ile şöyle bir amaç gütmüştür. Normalde (örneğin) 5 MB olacak görüntü dosya boyutunu 1 MB'a indirmek yerine görüntü dosya boyutunu gene 5 MB olarak hedefleyip içine sıkıştırılmadan önceki hali 25 MB olan bir görüntü sıkıştırmayı hedeflemişlerdir. Dolayısıyla siz dosya boyutu açısından net bir fark göremesenizde sanki fotoğraflarınız daha kaliteli çıkıyormuş izlenimine kapılıyorsunuz. Bu nedenle bu formatı rehberin ilerleyen kısımlarında kullanmayacağız. + +### AVIF (AV1 Image File Format) + +AVIF AV1 video codec'inin (önceki rehberimizde bajsettiğimiz) sıkıştırma tekniklerini kullanan modern bir görüntü formatıdır. Hem kayıplı hem de kayıpsız sıkıştırma seçenekleri sunar ve yüksek sıkıştırma oranları ile dikkat çeker. Modern tarayıcılar tarafından destekleniyor olsa da işletim sistemi ve dağıtıma göre bazen bir paket/eklenti yüklemek gerekebiliyor. Örneğin Windows'da Store üzerinden bir eklenti yüklenmesinden sonra bu formatla üretilmiş görüntüleri açabiliyorsunuz. + +# Sıkıştırma Tekniklerinin Kullanımı + +## Testlerde Kullanılacak Görüntüler + +Testlerde kullanılacak görüntüler için https://imagecompression.info/ adlı websitesini tercih ettim. Kalite farkının ve dosya boyutundaki olabilecek maksimum durumun net belirli olması açısından çok yüksek kaliteli ve hiç sıkıştırılmamış görüntüler seçtim. Kullandığım görüntü grubu [RGB-8Bit](https://imagecompression.info/test_images/) olarak belirtilmiş 14 adet renkli görüntüden ibaret. Bu görüntüler ayrıca aklımdaki çeşitli test koşullarının hepsine de uygun olduğu için ayrıca kendim görüntü üretmek zorunda kalmadım. Bu görseller websayfasında da belirtildiği üzere herhangi bir engelleyici telif hakkı kısıtlaması olmaksızın kullanılabilir. + +> These Images are available without any prohibitive copyright restrictions. +> These images are (c) there respective owners. You are granted full redistribution and publication rights on these images provided + +Görüntülerin bilgileri aşağıdaki gibidir: + +| No | Dosya Adı | Dosya Boyutu (Uzun) | Dosya Boyutu (Kısa) | +| :---: | :---: | :---: | :---: | +| 1 | artificial.ppm | 18874385 | 19M | +| 2 | big_building.ppm | 117158993 | 112M | +| 3 | big_tree.ppm | 83101217 | 80M | +| 4 | bridge.ppm | 33392120 | 32M | +| 5 | cathedral.ppm | 18048017 | 18M | +| 6 | deer.ppm | 32032706 | 31M | +| 7 | fireworks.ppm | 22127633 | 22M | +| 8 | flower_foveon.ppm | 10287665 | 9.9M | +| 9 | hdr.ppm | 18874385 | 19M | +| 10 | leaves_iso_1600.ppm | 18048017 | 18M | +| 11 | leaves_iso_200.ppm | 18048017 | 18M | +| 12 | nightshot_iso_100.ppm | 22127633 | 22M | +| 13 | nightshot_iso_1600.ppm | 22127633 | 22M | +| 14 | spider_web.ppm | 36363281 | 35M | +| \ | \ | / | / | +| Toplam | --- | 470611702 | 471M | + +## WebP Formatı (cwebp aracı) + +Bu formatta bir görüntü üretmek için önce gerekli olan `cwebp` aracını kurmamız gerekiyor. Kullandığınız dağıtıma göre değişmekle beraber Ubuntu/Fedora/Arch gibi ana dağıtımların repolarında direkt mevcut olup Windows kullanıcıları ise ilgili [websitesinden](https://developers.google.com/speed/webp/download?hl=tr) indirebileceklerdir. + +### Kurulum adımları + +1. **Ubuntu** + +``` +sudo apt-get install libwebp +``` + +2. **Fedora** + +``` +sudo dnf install libwebp-tools +``` + +3. **Arch** + +``` +sudo pacman -S libwebp +``` + +### Kullanılacak parametreler + +Cwebp aracının manual sayfasına baktığınızda çok fazla bir parametresi olmadığını göreceksiniz. Standart kullanım girdisi şu şekildedir: + +``` +cwebp input_file -o output_file.webp [options] +``` + +Bu hem son kullanıcı açısından oluşacak kafa karışıklığını ortadan kaldırıyor hem de araç ne vaadediyorsa sadece onu yapıyor. Bizim için gerekli olabilecek parametreler ise aşağıdaki gibidir: + +`-q sayı`: Çıktı olarak verilecek görüntünün kalite değerini ayarlamanızı sağlıyor. Değer olarak float girişi yapabilirsiniz fakat o kadar virgüllü sayılarla uğraşmaya değeceğini zannetmiyorum. Default olarak gelen değer değiştirmezseniz 75. Yani normal görüntüdeki detayların %75'i korunuyor. + +`-pass sayı`: Görüntünün yeniden oluşturulması sırasında yapılacak olan geçiş sayısını belirtiyor. Değer 0 ile 10 arasında bir tam sayı olarak belirtilmeli. Default değer 6. Dosya boyutuna ve kaliteye bir miktar etki ediyor. Değer ne kadar yüksek ise o kadar küçük dosya boyutunda o kadar yüksek kalite elde edilecektir. Sonuç olarak da maalesef dosya başına ayrılan işleme zamanı artacaktır. + +`-metadata metin`: (isteğe bağlı) Forumda sorulduğu için ekstra yer veriyorum. Metadata verilerinin ne kadarının tutulup tutulmayacağı konusunda karar vermenize yarayan parametre. Mümkün olan değerler `all`, `none`, `exif`, `icc`, `xmp`. Default değer ise `none`. Yani özellikle gerekmediği sürece değiştirmenizi önermemem. + +Sonuç olarak benim kullandığım komut mevcut parametreler dahil olmak üzere: + +``` +cwebp input_file -o output_file.webp -q 75 -pass 10 +``` + +## Avif (avifenc aracı) + +Bu formatta bir görüntü üretmek için de bir önceki formatımızda olduğu gibi bir araç gerektiriyor. Gerekli olan aracımızın adı `avifenc`. Gene kullandığınız dağıtıma göre değişmekle beraber Ubuntu/Fedora/Arch gibi ana dağıtımların repolarında direkt mevcut. Windows kullanıcıları bu sefer projenin [Github sayfasından](https://github.com/AOMediaCodec/libavif/releases) son sunulmuş release'i indirmesi gerekecektir. + +### Kurulum adımları + +1. **Ubuntu** + +``` +sudo apt-get install libavif-bin +``` + +2. **Fedora** + +``` +sudo dnf install libavif-tools +``` + +3. **Arch** + +``` +sudo pacman -S libavif +``` + +### Kullanılacak parametreler + +Avifenc aracının manual sayfası önceki araca göre biraz daha uzun ve bence kafa karıştırabilecek olmasına rağmen ihtiyacımız olacak parametreler gene çok fazla değil. Örneğin standart kullanımı gene benzer şekilde: + +``` +avifenc input_file output.avif [options] +``` + +Bu bize her iki araç açısından bir benzerlik sunup nispeten işimizi kolaylaştırıyor. Bu sefer ihtiyacımız olabilecek parametreler ise aşağıdaki gibi: + +`--min sayı`: Renk için minimum quantizer değerini (niceleyiciyi) belirlememize yarayan değer. Sayı büyüdükçe kalite azalmakta dosya boyutu ise küçülmektedir. Kabul edilen değer aralığı 0 ile 63 arasıdır. 0 girilmesi durumunda kayıpsız çeviri yapılmaya çalışılır. Default değer 10'dur. + +`--max sayı`: Renk için minimum quantizer değerini (niceleyiciyi) belirlememize yarayan değer. Sayı büyüdükçe diğer parametre ile aynı etkiyi yapar. Kabul edilen değer aralığı yine 0 ile 63 arasıdır. 0 girilmesi durumunda kayıpsız çeviri yapılmaya çalışılır. Default değer 40'dur. + +Bir önceki aracımızın aksine avifenc tekil bir kalite değeri yerine bir kalite aralığını girdi olarak kabul ediyor. Bu şekilde de bazı yerlerde daha fazla sıkıştırma yaparken diğer yerlerde durumun özelliğine göre daha az sıkıştırma yaparak optimal dosya boyutu/kalite oranına ulaşmayı hedefler. Yaptığım testlere göre ama (net bilgi olmamakla birlikte) yaklaşık %60-65 civarına tekabül edecek bir kaliteden bahsedebiliriz. + +`--speed sayı`: Dosya değerlendirilirken kodlayıcının ne kadar hızlı hareket etmesi gerektiğini belirten değer. Ne kadar yavaş hareket ederse o kadar kaliteli yeniden kodlama ve düşük dosya boyutuna ulaşabilecekken tam tersi şekilde daha uzun bir süre (gerçekten uzun oluyor bazen) sonucunu doğuracaktır. Kabul edilen değer aralığı 0 ile 10 arasındadır. 0 en yavaş 10 en hızlıdır. Default değer 6'dır. + +`--jobs sayı`: Bu görev için oluşturulacak iş sayısını veya kullanılacak core/thread sayısını belirten değer. Linux kullanıcıları bu parametre ile aşinadır diye düşünüyorum. Girilebilecek değer aralığı CPU'nuza göre değişecek olup minimum değer 1 olup maksimum ve aynı zamanda da Default değer de `all` dır + +Sonuç olarak benim kullandığım komut mevcut parametreler dahil olmak üzere: + +``` +avifenc input_file output.avif --jobs all --speed 0 --min 10 --max 40 +``` + +## Çeviri Sonuçları + +Çeviri sırasında girdi olarak `.ppm` uzantılı ana test dosyalarımızın aynı zamanda `.ycbcr`, `.y4m`, `.tiff`, `.yuv` ve `.png` uzantılı kopyaları üretilmiştir. Bu kopyalar hem farklı formatlardan çeviri kalitesinin test edilmesi hem de ara formatların kullanılmasını gerektiren durumlar için hazırlanmıştır. Dosyaların hepsini websitesinde yer kaplamaması adına bir [Github Reposu'na](https://github.com/wiseweb-works/fotograf-cevirme) yükledim. ORadan direkt ulaşabilir ve isterseniz indirebilirisiniz. + +Avif açısından farklı `--speed` değerlerinin etkisinin de anlaşılması için 0, 6 ve 10 değerleri için ayrı ayrı çeviriler yapılmıştır. + +Webp açısından ise speed parametresi olmadığı ve pass parametresi hızı çok etkilemediği için tüm çevirilerde pass değeri 10 olarak alınmıştır. + +Aşağıda her bir örnek fotoğraf açısından çeviri sonuçlarını bulabilirsiniz. Çok yer kaplaması için ilk fotoğraftan sonrasını görmek için genişlet butonuna tıklamanız gerekmektedir. + +| Dosya Adı | Dosya Boyutu (Uzun) | Dosya Boyutu (Kısa) | Oran % | +| :---: | :---: | :---: | :---: | +| artificial.ppm | 18874385 | 19M | Dosya aslı | +| artificial.ycbcr | 18874368 | 19M | 100,00 | +| artificial.y4m | 18874446 | 19M | 100,00 | +| artificial.tiff | 18874784 | 19M | 100,00 | +| artificial.yuv | 12582912 | 12M | 66,67 | +| artificial.png | 1656508 | 1.6M | 8,78 | +| artificial_speed0.avif | 149028 | 146K | 0,79 | +| artificial_speed10.avif | 299051 | 293K | 1,58 | +| artificial_speed6.avif | 168926 | 165K | 0,90 | +| artificial.webp | 229228 | 224K | 1,21 | + +
+ Diğer görüntüler için tıklayınız + + | Dosya Adı | Dosya Boyutu (Uzun) | Dosya Boyutu (Kısa) | Oran % | + | :---: | :---: | :---: | :---: | + | big_building.ppm | 117158993 | 112M | Dosya aslı | | + | big_building.ycbcr | 117158976 | 112M | 100,00| | + | big_building.y4m | 117159054 | 112M | 100,00| | + | big_building.tiff | 117160144 | 112M | 100,00| | + | big_building.yuv | 78105984 | 75M | 66,67| | + | big_building.png | 62150284 | 60M | 53,05| | + | big_building_speed0.avif | 3014156 | 2.9M | 2,57| | + | big_building_speed10.avif | 2959255 | 2.9M | 2,53| | + | big_building_speed6.avif | 2943252 | 2.9M | 2,51| | + | big_building.webp | 3414240 | 3.3M | 2,91| | + + | Dosya Adı | Dosya Boyutu (Uzun) | Dosya Boyutu (Kısa) | Oran % | + | :---: | :---: | :---: | :---: | + | big_tree.ppm | 83101217 | 80M | Dosya aslı | + | big_tree.ycbcr | 83101200 | 80M | 100,00 | + | big_tree.y4m | 83101278 | 80M | 100,00 | + | big_tree.tiff | 83102224 | 80M | 100,00 | + | big_tree.yuv | 55400800 | 53M | 66,67 | + | big_tree.png | 48100895 | 46M | 57,88 | + | big_tree_speed0.avif | 3253303 | 3.2M | 3,91 | + | big_tree_speed10.avif | 2982856 | 2.9M | 3,59 | + | big_tree_speed6.avif | 3033840 | 2.9M | 3,65 | + | big_tree.webp | 2167850 | 2.1M | 2,61 | + + | Dosya Adı | Dosya Boyutu (Uzun) | Dosya Boyutu (Kısa) | Oran % | + | :---: | :---: | :---: | :---: | + | bridge.ppm | 33392120 | 32M | Dosya aslı | + | bridge.ycbcr | 33392103 | 32M | 100,00 | + | bridge.y4m | 33392181 | 32M | 100,00 | + | bridge.tiff | 33392624 | 32M | 100,00 | + | bridge.yuv | 22269500 | 22M | 66,69 | + | bridge.png | 19747093 | 19M | 59,14 | + | bridge_speed0.avif | 1411838 | 1.4M | 4,23 | + | bridge_speed10.avif | 1262682 | 1.3M | 3,78 | + | bridge_speed6.avif | 1323802 | 1.3M | 3,96 | + | bridge.webp | 1083864 | 1.1M | 3,25 | + + | Dosya Adı | Dosya Boyutu (Uzun) | Dosya Boyutu (Kısa) | Oran % | + | :---: | :---: | :---: | :---: | + | cathedral.ppm | 18048017 | 18M | Dosya aslı | + | cathedral.ycbcr | 18048000 | 18M | 100,00 | + | cathedral.y4m | 18048078 | 18M | 100,00 | + | cathedral.tiff | 18048416 | 18M | 100,00 | + | cathedral.yuv | 12032000 | 12M | 66,67 | + | cathedral.png | 9352750 | 9.0M | 51,82 | + | cathedral_speed0.avif | 374017 | 366K | 2,07 | + | cathedral_speed10.avif | 349586 | 342K | 1,94 | + | cathedral_speed6.avif | 345661 | 338K | 1,92 | + | cathedral.webp | 361172 | 353K | 2,00 | + + | Dosya Adı | Dosya Boyutu (Uzun) | Dosya Boyutu (Kısa) | Oran % | + | :---: | :---: | :---: | :---: | + | deer.ppm | 32032706 | 31M | Dosya aslı | + | deer.ycbcr | 32032689 | 31M | 100,00 | + | deer.y4m | 32032767 | 31M | 100,00 | + | deer.tiff | 32033226 | 31M | 100,00 | + | deer.yuv | 21360408 | 21M | 66,68 | + | deer.png | 21196494 | 21M | 66,17 | + | deer_speed0.avif | 1730016 | 1.7M | 5,40 | + | deer_speed10.avif | 1713279 | 1.7M | 5,35 | + | deer_speed6.avif | 1660326 | 1.6M | 5,18 | + | deer.webp | 994750 | 972K | 3,11 | + + | Dosya Adı | Dosya Boyutu (Uzun) | Dosya Boyutu (Kısa) | Oran % | + | :---: | :---: | :---: | :---: | + | fireworks.ppm | 22127633 | 22M | Dosya aslı | + | fireworks.ycbcr | 22127616 | 22M | 100,00 | + | fireworks.y4m | 22127694 | 22M | 100,00 | + | fireworks.tiff | 22128048 | 22M | 100,00 | + | fireworks.yuv | 14751744 | 15M | 66,67 | + | fireworks.png | 5642881 | 5.4M | 25,50 | + | fireworks_speed0.avif | 149166 | 146K | 0,67 | + | fireworks_speed10.avif | 187413 | 184K | 0,85 | + | fireworks_speed6.avif | 154956 | 152K | 0,70 | + | fireworks.webp | 183674 | 180K | 0,83 | + + | Dosya Adı | Dosya Boyutu (Uzun) | Dosya Boyutu (Kısa) | Oran % | + | :---: | :---: | :---: | :---: | + | flower_foveon.ppm | 10287665 | 9.9M | Dosya aslı | + | flower_foveon.ycbcr | 10287648 | 9.9M | 100,00 | + | flower_foveon.y4m | 10287726 | 9.9M | 100,00 | + | flower_foveon.tiff | 10288000 | 9.9M | 100,00 | + | flower_foveon.yuv | 6858432 | 6.6M | 66,67 | + | flower_foveon.png | 3131970 | 3.0M | 30,44 | + | flower_foveon_speed0.avif | 54972 | 54K | 0,53 | + | flower_foveon_speed10.avif | 68146 | 67K | 0,66 | + | flower_foveon_speed6.avif | 58684 | 58K | 0,57 | + | flower_foveon.webp | 70382 | 69K | 0,68 | + + | Dosya Adı | Dosya Boyutu (Uzun) | Dosya Boyutu (Kısa) | Oran % | + | :---: | :---: | :---: | :---: | + | hdr.ppm | 18874385 | 19M | Dosya aslı | + | hdr.ycbcr | 18874368 | 19M | 100,00 | + | hdr.y4m | 18874446 | 19M | 100,00 | + | hdr.tiff | 18874784 | 19M | 100,00 | + | hdr.yuv | 12582912 | 12M | 66,67 | + | hdr.png | 6974764 | 6.7M | 36,95 | + | hdr_speed0.avif | 114743 | 113K | 0,61 | + | hdr_speed10.avif | 132916 | 130K | 0,70 | + | hdr_speed6.avif | 117136 | 115K | 0,62 | + | hdr.webp | 143366 | 141K | 0,76 | + + | Dosya Adı | Dosya Boyutu (Uzun) | Dosya Boyutu (Kısa) | Oran % | + | :---: | :---: | :---: | :---: | + | leaves_iso_1600.ppm | 18048017 | 18M | Dosya aslı | + | leaves_iso_1600.ycbcr | 18048000 | 18M | 100,00 | + | leaves_iso_1600.y4m | 18048078 | 18M | 100,00 | + | leaves_iso_1600.tiff | 18048408 | 18M | 100,00 | + | leaves_iso_1600.yuv | 12032000 | 12M | 66,67 | + | leaves_iso_1600.png | 11327915 | 11M | 62,77 | + | leaves_iso_1600_speed0.avif | 1108271 | 1.1M | 6,14 | + | leaves_iso_1600_speed10.avif | 964810 | 943K | 5,35 | + | leaves_iso_1600_speed6.avif | 1013569 | 990K | 5,62 | + | leaves_iso_1600.webp | 883776 | 864K | 4,90 | + + | Dosya Adı | Dosya Boyutu (Uzun) | Dosya Boyutu (Kısa) | Oran % | + | :---: | :---: | :---: | :---: | + | leaves_iso_200.ppm | 18048017 | 18M | Dosya aslı | + | leaves_iso_200.ycbcr | 18048000 | 18M | 100,00 | + | leaves_iso_200.y4m | 18048078 | 18M | 100,00 | + | leaves_iso_200.tiff | 18048408 | 18M | 100,00 | + | leaves_iso_200.yuv | 12032000 | 12M | 66,67 | + | leaves_iso_200.png | 10110529 | 9.7M | 56,02 | + | leaves_iso_200_speed0.avif | 780224 | 762K | 4,32 | + | leaves_iso_200_speed10.avif | 757813 | 741K | 4,20 | + | leaves_iso_200_speed6.avif | 762472 | 745K | 4,22 | + | leaves_iso_200.webp | 720154 | 704K | 3,99 | + + | Dosya Adı | Dosya Boyutu (Uzun) | Dosya Boyutu (Kısa) | Oran % | + | :---: | :---: | :---: | :---: | + | nightshot_iso_100.ppm | 22127633 | 22M | Dosya aslı | + | nightshot_iso_100.ycbcr | 22127616 | 22M | 100,00 | + | nightshot_iso_100.y4m | 22127694 | 22M | 100,00 | + | nightshot_iso_100.tiff | 22128048 | 22M | 100,00 | + | nightshot_iso_100.yuv | 14751744 | 15M | 66,67 | + | nightshot_iso_100.png | 7635953 | 7.3M | 34,51 | + | nightshot_iso_100_speed0.avif | 157003 | 154K | 0,71 | + | nightshot_iso_100_speed10.avif | 213297 | 209K | 0,96 | + | nightshot_iso_100_speed6.avif | 161694 | 158K | 0,73 | + | nightshot_iso_100.webp | 223064 | 218K | 1,01 | + + | Dosya Adı | Dosya Boyutu (Uzun) | Dosya Boyutu (Kısa) | Oran % | + | :---: | :---: | :---: | :---: | + | nightshot_iso_1600.ppm | 22127633 | 22M | Dosya aslı | + | nightshot_iso_1600.ycbcr | 22127616 | 22M | 100,00 | + | nightshot_iso_1600.y4m | 22127694 | 22M | 100,00 | + | nightshot_iso_1600.tiff | 22128048 | 22M | 100,00 | + | nightshot_iso_1600.yuv | 14751744 | 15M | 66,67 | + | nightshot_iso_1600.png | 12520345 | 12M | 56,58 | + | nightshot_iso_1600_speed0.avif | 789712 | 772K | 3,57 | + | nightshot_iso_1600_speed10.avif | 686661 | 671K | 3,10 | + | nightshot_iso_1600_speed6.avif | 703014 | 687K | 3,18 | + | nightshot_iso_1600.webp | 576746 | 564K | 2,61 | + + | Dosya Adı | Dosya Boyutu (Uzun) | Dosya Boyutu (Kısa) | Oran % | + | :---: | :---: | :---: | :---: | + | spider_web.ppm | 36363281 | 35M | Dosya aslı | + | spider_web.ycbcr | 36363264 | 35M | 100,00 | + | spider_web.y4m | 36363342 | 35M | 100,00 | + | spider_web.tiff | 36363816 | 35M | 100,00 | + | spider_web.yuv | 24242176 | 24M | 66,67 | + | spider_web.png | 10272309 | 9.8M | 28,25 | + | spider_web_speed0.avif | 106255 | 104K | 0,29 | + | spider_web_speed10.avif | 126188 | 124K | 0,35 | + | spider_web_speed6.avif | 113351 | 111K | 0,31 | + | spider_web.webp | 165030 | 162K | 0,45 | + +
+ +Sonuçlara bakıldığında dosya boyutunu (en büyük dosyaya göre) %1-5'ine kadar azaltabildiğini görüyoruz. Fakat gerçek dünyada bu tip RAW dosya formatları veya hiç sıkıştırılmamış dosyalar kullanmaıdğımız için bu derece bir boyut azalmasını görmeniz zor. Fakat png veya jpg uzantıları açısından değerlendirirsek dosya boyutunı %10-33 aralığına kadar düşürebildiğini çok rahat söyleyebiliriz. Gerçek dünya testlerinde de bu sonuçları görmeniz çok muhtemel. + +# Otomatikleştirilmiş Hali: Imagemagick + +||| +|:---:|:---:| +![1](/images/fotograf-compress-magick/mid1.png) | ![2](/images/fotograf-compress-magick/mid2.png) + +Imagemagick [ImageMagick Studio LLC](https://imagemagick.org/) tarafından geliştirilen ve [açık kaynaklı](https://github.com/ImageMagick/ImageMagick) bir yazılımdır. Yazılımın lisansı mevcut olarak Github'da kullanılan o veya şu lisans diye net olarak söyleyemiyorum. Bir kısım yerlerde Apache 2.0 Lisansına çok yakın olduğunu söylemiş olsalar da tam bilgi için [LICENSE](https://raw.githubusercontent.com/ImageMagick/ImageMagick/main/LICENSE) dosyasına göz atmanızı öneririm. + +Yazılımın odaklandığı ve çözmek istediği sorun fotoğraf ve benzeri dağıtım formatlarını dönüştürürken ve yukarıda bahsettiğim gibi yazılımları kullanmadan, teknik bilgilerle çok boğuşmadan ve istediğimiz sonuca bizi ulaştıracak bir program üretmek. Yazılımı herhangi bir linux dağıtımında indirmek istediğiniz zaman bağımlılık olarak birçok görüntü formatı/kütüphanesi birlikte iniyor ve sizi ek yazılımları tespit edip indirme gerekliliğinden kurtarıyor. Yazılım rehberin paylaşıldığı tarih itibariyle çalışma mantığı tüm araçlar açısından tekil bir parametre sistemi getirme ve gerekirse sizin verdiğiniz parametreyi gerekli aracın anlayacağı şekle dönüştürmek. Örneğin bir araç kalite için `-q` diğeri `--quality` diğeri `-Q` kullanıyor dahi olsa program bunları ezberlemenizi gerektirmiyor. Siz hangi formattan hangi formata dönüştürecek olursanız olun `-quality değer` parametresi ile bu sonuca ulaşabiliyorsunuz. İlk ve en önemli özelliği bu. + +Bu yazılımı bulmadan önce kendim tüm bu araçlar açısından gerekli kütüphaneleri elle yüklüyor, hangi araç hangi formatları kabul ediyor bunu takip ediyor ve gerekirse ara formatlar üretiyordum. Mesela avif ppm den dönüşüme izin vermezken y4m den izin veriyor. Tam tersine cwebp ppm den dönüşüme izin verirken mesela ycbcr den dönüşüme izin vermiyor gibi. Fakat imagemagick aracını kullanırken bunları düşünmenize gerek yok. Çünkü o sizin için ara formatları kayıpszı bir şekilde oluşturup dosyanızı hedef formata dönüştürüyor ve gereksiz geçici dosyaları siliyor. Tüm bu anlattıklarım ise birkaç saniye içinde oluyor. Bu da sizin işinizi kolaylaştıracak ikinci güzel özelliği. + +Bahsetmeyi değer bulduğum üçüncü özelliği ise toplu dosya çevirme veya başka tabirle batch convert. Bahsettiğim diğer araçların ve bahsi geçmeyen birçok aracın en büyük eksikliği toplu olarak dosya seçmenize izin vermemesi. Hepsi kendi için tek tek dosya çevirme üzerine odaklanmışlardır. Aşağıdakine benzer bir komut ile toplu çeviri yapmaları mümkün olmasına rağmen bu hem son kullanıcı açısından anlaması pek kolay olmadığı gibi her zaman için de uygulanması mümkün olmamaktadır. + +Örnek komut (jpg --> webp): `find ./ -type f -name '*.jpg' -exec sh -c 'cwebp $1 -o "${1%.jpg}.webp" [options]' _ {} \;` + +Fakat imagemagick aracımızda ise bu süreç çok daha kolay. Örnek komut (jpg --> webp): `magick mogrify -format webp -quality 90 *.jpg` ne kadar anlaşılır ve kolay değil mi gerçekten. Giriş verisi olarak birden fazla dosya seçilebildiği gibi çıkış formatı olarak da birden fazla dosya formatı seçilebilir. Örneğin bir klasördeki tüm JPG/PNG uzantılı fotoğraflarınızı webp ve avif uzantısına tek komut ile çevirebiliyorsunuz. Bu gerçekten süper bir imkan. + +## Yazılımın indirilmesi ve/veya kurulması + +Yazılım Linux, Mac, iOS ve Windows'u desteklemektedir. Windows için [exe uzantılı dosyayı](https://imagemagick.org/script/download.php#windows) indirip kullanabilirsiniz. + +Arch kullanıyorsanız: + +``` +sudo pacman -S imagemagick +``` + +Ubuntu kullanıyorsanız: + +``` +sudo apt-get install imagemagick +``` + +Fedora kullanıyorsanız: + +``` +sudo dnf install ImageMagick +``` + +Diğer linux dağıtımı kullanıcıları ise binary dosyası olarak indirebilir veya kendisi derleyebilir. Yükleme ile ilgili [talimatlara](https://imagemagick.org/script/install-source.php) Web sayfasından ulaşabilirsiniz. + +## Yazılımın ayarları + +Yazılımı kurduktan sonra `man magick` komutu ile yardım kısmına veya ayrıntılı bilgiye ulaşabilirsiniz. Sizi yaklaşık olarak (bir kısmını kırptım) şöyle bir ekran karşılayacaktır: + +``` +magick(1) +General Commands Manual +magick(1) + +NAME + magick - convert between image formats as well as resize an image, blur, crop, despeckle, dither, draw on, flip, join, re-sample, and much more. + +SYNOPSIS + magick [input-options] input-file [output-options] output-file +.... + +DESCRIPTION +.... + + -define format:option +.... + -preview type image preview type + -quality value JPEG/MIFF/PNG compression level +.... + -quiet suppress all warning messages + -verbose print detailed information about the image + -auto-orient automatically orient image + -strip strip image of all profiles and comments +.... + Miscellaneous Options: + -debug events display copious debugging information + -help print program options + -log format format of debugging information + -list type print a list of supported option arguments + -version print version information + + Use any setting or operator as an output-option. Only a limited number of setting are input-option. They include: -antialias, -caption, -density, -define, -encoding, -font, -pointsize, -size, and -texture as well as any of the + miscellaneous options. + + By default, the image format of ‘file' is determined by its magic number. To specify a particular image format, precede the filename with an image format name and a colon (i.e. ps:image) or specify the image type as the file‐ + name suffix (i.e. image.ps). Specify 'file' as '-' for standard input or output. + +SEE ALSO + ImageMagick(1) + +COPYRIGHT + Copyright (C) 1999 ImageMagick Studio LLC. Additional copyrights and licenses apply to this software, see file:///usr/share/doc/ImageMagick-7/www/license.html or https://imagemagick.org/script/license.php +``` + +### Tekil dosya çevirme + +En basit kullanım senaryosunda tek dosya çevirmek isterseniz aşağıdaki gibi kullanabilirsiniz. + +JPG/JPEG'den WebP'ye dönüştürme +``` +magick input.jpg -quality 75 output.webp +``` + +JPG/JPEG'den Avif'e dönüştürme +``` +magick input.jpg -quality 75 output.avif +``` + +Gördüğünüz üzere komut çok az değişti. Quality değerini örnek olarak o şekilde belirledim. Siz birkaç fotoğraf üzerinden deneme yapıp sizin için en uygun değeri rahatlıkla bulabilirsiniz. Peki ben nasıl kullanıyorum veya hangi parametreleri kullanıyorum diye soracak olursanız eğer: + +WebP için: + +``` +magick input.jpg -define webp:pass=10 -quality 75 output.webp +``` + +Avif için: + +``` +magick input.jpg -define avif:speed=0 -quality 75 output.avif +``` + +Buradaki `-define format:parametre` girdisi ilgili araç için ek bir özel parametre girmek istiyorsanız kullanılıyor. Bu iki araç açısından gerekli parametreleri daha iyi bildiğim için halen eski düzen böyle devam ediyorum. + +### Çoklu dosya çevirme + +Çoklu dosya çevirmek istediğiniz senaryoda gerekli en basit komutlar aşağıdaki gibidir: + + +JPG/JPEG'den WebP'ye dönüştürme +``` +magick mogrify -format webp -quality 75 *.jpg +``` + +JPG/JPEG'den Avif'e dönüştürme +``` +magick mogrify -format avif -quality 75 *.jpg +``` + +Komut gene çok az değişti ve okunabilirlik açısından da halen çok iyi bir durumda. Benim kullandığım tam komut ne diye soracak olursanız gene aynı parametreleri eklemiş olacağım ve şöyle görünecek: + +WebP için: + +``` +magick mogrify -format webp -define webp:pass=10 -quality 75 *.jpg +``` + +Avif için: + +``` +magick mogrify -format avif -define avif:speed=0 -quality 75 *.jpg +``` + +### Gerçek dünya testleri + +Imagemagick aracı kağıt üstünde diğer araçların yaptığı şeyin aynısını yapıyor görünüyor. Fakat akıldaki hesap her zaman gerçekle uyuşmadığı için ve bunca yazının da gerçekten işe yarayıp yaramadığından emin olmak için test etmek iyi olacaktır. Bu nedenle bir haftasonu gezisi sırasında çekmiş olduğum boyutları 1.6M ile 4.4M arasında değişen 8-Bit/RGB/JPG/4096x2304 özelliklerine sahip 36 adet fotoğrafı bu araç ile sıkıştıracağım. + +| Dosya Adı | Dosya Boyutu (Uzun) | Dosya Boyutu (Kısa) | Oran % | +| :---: | :---: | :---: | :---: | +| IMG-1.jpg | 3123535 | 3.0M | Dosya Aslı | +| IMG-1.avif | 1504064 | 1.5M | 48,15 | +| IMG-1.webp | 1076958 | 1.1M | 34,48 | +| IMG-2.jpg | 2790604 | 2.7M | Dosya Aslı | +| IMG-2.avif | 550187 | 538K | 19,72 | +| IMG-2.webp | 391096 | 382K | 14,01 | +| IMG-3.jpg | 3150447 | 3.1M | Dosya Aslı | +| IMG-3.avif | 766041 | 749K | 24,32 | +| IMG-3.webp | 546460 | 534K | 17,35 | +| IMG-4.jpg | 4526481 | 4.4M | Dosya Aslı | +| IMG-4.avif | 1743551 | 1.7M | 38,52 | +| IMG-4.webp | 1218140 | 1.2M | 26,91 | + +
+ Diğer görüntüler için lütfen tıklayınız + + | Dosya Adı | Dosya Boyutu (Uzun) | Dosya Boyutu (Kısa) | Oran % | + | :---: | :---: | :---: | :---: | + | IMG-5.jpg | 4229066 | 4.1M | Dosya Aslı | + | IMG-5.avif | 1519081 | 1.5M | 35,92 | + | IMG-5.webp | 1063014 | 1.1M | 25,14 | + | IMG-6.jpg | 3159689 | 3.1M | Dosya Aslı | + | IMG-6.avif | 1500718 | 1.5M | 47,50 | + | IMG-6.webp | 1077274 | 1.1M | 34,09 | + | IMG-7.jpg | 3173451 | 3.1M | Dosya Aslı | + | IMG-7.avif | 1503358 | 1.5M | 47,37 | + | IMG-7.webp | 1069566 | 1.1M | 33,70 | + | IMG-8.jpg | 3757624 | 3.6M | Dosya Aslı | + | IMG-8.avif | 1986912 | 1.9M | 52,88 | + | IMG-8.webp | 1465148 | 1.4M | 38,99 | + | IMG-9.jpg | 3039928 | 2.9M | Dosya Aslı | + | IMG-9.avif | 1424021 | 1.4M | 46,84 | + | IMG-9.webp | 1028336 | 1005K | 33,83 | + | IMG-10.jpg | 2441091 | 2.4M | Dosya Aslı | + | IMG-10.avif | 902915 | 882K | 36,99 | + | IMG-10.webp | 611696 | 598K | 25,06 | + | IMG-11.jpg | 2526240 | 2.5M | Dosya Aslı | + | IMG-11.avif | 971978 | 950K | 38,48 | + | IMG-11.webp | 672250 | 657K | 26,61 | + | IMG-12.jpg | 3010868 | 2.9M | Dosya Aslı | + | IMG-12.avif | 1363342 | 1.4M | 45,28 | + | IMG-12.webp | 1003464 | 980K | 33,33 | + | IMG-13.jpg | 2894166 | 2.8M | Dosya Aslı | + | IMG-13.avif | 1262222 | 1.3M | 43,61 | + | IMG-13.webp | 903482 | 883K | 31,22 | + | IMG-14.jpg | 2794211 | 2.7M | Dosya Aslı | + | IMG-14.avif | 1180628 | 1.2M | 42,25 | + | IMG-14.webp | 845948 | 827K | 30,28 | + | IMG-15.jpg | 2698751 | 2.6M | Dosya Aslı | + | IMG-15.avif | 1625281 | 1.6M | 60,22 | + | IMG-15.webp | 1147432 | 1.1M | 42,52 | + | IMG-16.jpg | 2858864 | 2.8M | Dosya Aslı | + | IMG-16.avif | 1778962 | 1.7M | 62,23 | + | IMG-16.webp | 1269262 | 1.3M | 44,40 | + | IMG-17.jpg | 2679597 | 2.6M | Dosya Aslı | + | IMG-17.avif | 1604076 | 1.6M | 59,86 | + | IMG-17.webp | 1127914 | 1.1M | 42,09 | + | IMG-18.jpg | 1664310 | 1.6M | Dosya Aslı | + | IMG-18.avif | 305830 | 299K | 18,38 | + | IMG-18.webp | 211652 | 207K | 12,72 | + | IMG-19.jpg | 3007566 | 2.9M | Dosya Aslı | + | IMG-19.avif | 1393500 | 1.4M | 46,33 | + | IMG-19.webp | 941406 | 920K | 31,30 | + | IMG-20.jpg | 2097444 | 2.1M | Dosya Aslı | + | IMG-20.avif | 582060 | 569K | 27,75 | + | IMG-20.webp | 456522 | 446K | 21,77 | + | IMG-21.jpg | 2852271 | 2.8M | Dosya Aslı | + | IMG-21.avif | 1275593 | 1.3M | 44,72 | + | IMG-21.webp | 887504 | 867K | 31,12 | + | IMG-22.jpg | 2757359 | 2.7M | Dosya Aslı | + | IMG-22.avif | 1181807 | 1.2M | 42,86 | + | IMG-22.webp | 847800 | 828K | 30,75 | + | IMG-23.jpg | 2312096 | 2.3M | Dosya Aslı | + | IMG-23.avif | 817076 | 798K | 35,34 | + | IMG-23.webp | 579860 | 567K | 25,08 | + | IMG-24.jpg | 3550795 | 3.4M | Dosya Aslı | + | IMG-24.avif | 1871401 | 1.8M | 52,70 | + | IMG-24.webp | 1404298 | 1.4M | 39,55 | + | IMG-25.jpg | 3203733 | 3.1M | Dosya Aslı | + | IMG-25.avif | 1381699 | 1.4M | 43,13 | + | IMG-25.webp | 1184984 | 1.2M | 36,99 | + | IMG-26.jpg | 3174471 | 3.1M | Dosya Aslı | + | IMG-26.avif | 1354947 | 1.3M | 42,68 | + | IMG-26.webp | 1148438 | 1.1M | 36,18 | + | IMG-27.jpg | 3341253 | 3.2M | Dosya Aslı | + | IMG-27.avif | 1511043 | 1.5M | 45,22 | + | IMG-27.webp | 1236658 | 1.2M | 37,01 | + | IMG-28.jpg | 3588628 | 3.5M | Dosya Aslı | + | IMG-28.avif | 1916504 | 1.9M | 53,40 | + | IMG-28.webp | 1454832 | 1.4M | 40,54 | + | IMG-29.jpg | 2356713 | 2.3M | Dosya Aslı | + | IMG-29.avif | 1431777 | 1.4M | 60,75 | + | IMG-29.webp | 1030610 | 1007K | 43,73 | + | IMG-30.jpg | 3075593 | 3.0M | Dosya Aslı | + | IMG-30.avif | 1487599 | 1.5M | 48,37 | + | IMG-30.webp | 1069446 | 1.1M | 34,77 | + | IMG-31.jpg | 2620141 | 2.5M | Dosya Aslı | + | IMG-31.avif | 1053561 | 1.1M | 40,21 | + | IMG-31.webp | 788630 | 771K | 30,10 | + | IMG-32.jpg | 2793081 | 2.7M | Dosya Aslı | + | IMG-32.avif | 1234183 | 1.2M | 44,19 | + | IMG-32.webp | 903448 | 883K | 32,35 | + | IMG-33.jpg | 2648478 | 2.6M | Dosya Aslı | + | IMG-33.avif | 1100654 | 1.1M | 41,56 | + | IMG-33.webp | 826504 | 808K | 31,21 | + | IMG-34.jpg | 3181983 | 3.1M | Dosya Aslı | + | IMG-34.avif | 1497755 | 1.5M | 47,07 | + | IMG-34.webp | 1130016 | 1.1M | 35,51 | + | IMG-35.jpg | 2580106 | 2.5M | Dosya Aslı | + | IMG-35.avif | 1050044 | 1.1M | 40,70 | + | IMG-35.webp | 790866 | 773K | 30,65 | + | IMG-36.jpg | 2922206 | 2.8M | Dosya Aslı | + | IMG-36.avif | 1338502 | 1.3M | 45,80 | + | IMG-36.webp | 980454 | 958K | 33,55 | + +
+ +Sonuç olarak: +* JPG'de toplam dosya boyutu: 106582840 yani 107M +* WebP ile toplam dosya boyutu: 34391368 yani 35M (%32,26) +* Avif ile toplam dosya boyutu: 46972872 yani 47M (%44,07) + +Kısa bir değerlendirme ile orijinal araçların yaptığı kadar yüksek verimliliğe ulaşamasa da dikkate ve uygulamaya değer bir kazanım elde edebiliyoruz. + +## Anlatım dışı bırakılan kısımlar + +Bu rehberde elde edilen verim yeterli görüldüğü için `Color Space`, `Chroma Subsampling`, `Sampling Factor Geometry`, `Posterize`, `Iteration`, `Transparent Color` ve `Solorize` kavramları ile çalışılmamış default olan değerler kullanılmıştır. Bu kavramlara biraz daha aşina olup isteğe göre daha iyi sonuçlar elde etmek mümkün olup tek başına `Posterize` değerini değiştirerek bile çok güzel sonuçlar elde ettim. Fakat anlatması ve uygun değerin tespit edilmesi çok kolay olmadığı için bu rehber kapsamı dışında bırakılmıştır. + +## Fotoğraf sıkıştırma ile ilgili forumda açılmış konular + +Bu rehberin haricinde spesifik olarak (diğer rehberlerde de olduğu üzere) fotoğraf çevirme konuları ve imagemagick ilgili yaşanan sorunları veya ek rehberleri bu konu açısından fayda göstermesi durumunda atıf yapacağım. Ayrıca benim eklediğim konular dışındaki imagemagick ile ilgili tüm konulara #imagemagick veya #magick etiketine tıklayarak ulaşabilirsiniz. + +# Son Söz ve Kaynakça + +Artık elimdeki bu fotoğrafları ne yapacağım acaba bir hard disk mi alsam gibi soruları kendinize sormanıza gerek kalmadı. Bu rehber sonucunda sizi bir süre daha götürecek kadar yer kazanmış oldunuz. Ayrıca sadece jpg değil kullanamadığınız tüm formatlar özelinde istediğiniz formata kolayca çevirmeyi de öğrenmiş oldunuz. Umarım keyifli bir rehber olmuştur. Rehberin teknik açıklaması veya içeriği ile ilgili bir eksiklik/hata görmeniz durumunda bana bildirebilir veya düzeltilmesi için cevap olarak yazabilirsiniz. Bir sonraki rehbere kadar iyi seyirler ve esenlikler dileğiyle. + +Kaynaklar: +1. https://tez.yok.gov.tr/UlusalTezMerkezi/ Tez No: 183894 (Veri sıkıştırmada yeni yöntemler, ALTAN MESUT, 2006) +2. https://tez.yok.gov.tr/UlusalTezMerkezi/ Tez No: 565227 (Tekrarlı uzunluk kodlaması (RLE) ve ayrıştırma esaslı görüntü sıkıştırma, MUSTAFA BURAK KALKAN, 2019) +3. https://pnrsolution.org/Datacenter/Vol3/Issue2/129.pdf (Image Compression Techniques: Lossy and Lossless, ROJATKAR/BORKAR/NAIK/PEDDIWAR, 2015) +4. https://arxiv.org/pdf/1101.0395 (Improving the Performance of K-Means for Color Quantization, M. Emre CELEBİ, 2011) +5. https://scikit-learn.org/stable/auto_examples/cluster/plot_color_quantization.html +6. https://developers.google.com/speed/webp/docs/cwebp +7. https://github.com/AOMediaCodec/libavif/blob/main/doc/avifenc.1.md +8. https://imagemagick.org/script/magick.php +9. https://imagemagick.org/script/convert.php +10. https://www.youtube.com/watch?v=Q2aEzeMDHMA (JPEG DCT, Discrete Cosine Transform (JPEG Pt2) | Computerphile) +11. https://www.youtube.com/watch?v=F1kYBnY6mwg (Image compression deep-dive | Chrome for Developers) +12. https://www.youtube.com/watch?v=_ciMMmxNIGw (Image Compression - EE 274, Data Compression, L15 | Stanford Research Talks) +13. İlk Yayım: [BTT](https://btt.community/t/fotograf-sikistirma-yontemleri-inceleme-ve-rehber/8315) \ No newline at end of file diff --git a/content/post/grigori-rasputin.md b/content/post/grigori-rasputin.md index 809d014d..b28d7ee6 100644 --- a/content/post/grigori-rasputin.md +++ b/content/post/grigori-rasputin.md @@ -1,20 +1,20 @@ ---- -title: "Grigori Rasputin ve aynı isimli şarkı hk" -date: 2020-05-01 -tags: ["müzik", "rasputin", "konu dışı", "ilginç"] -author: "Wise" -draft: false ---- -Nerede doğduğunu bilmediğimiz Grigori Rasputin isimli bu arkadaşın çocukluk yılları daha çok Sibirya geçiyor. Mavi gözleri ve etkileyici mimikleri var. Daha küçük yaştan itibaren insanları etkilemeyi ve ilgi çekmeyi başaran bir yapısı mevcut. Hatta bir keresinde yaşı küçük olmasına rağmen babasının çiftliğinden çalınan bir atı kimin çaldığını kehanet yoluyla tahmin eder. Herkes (babası da dahil) Rasputin’e inanmamış olsa da sonradan hırsız kendisi gelip suçunu itiraf eder. Bu olaydan sonra ailesi ve bütün çevresi onun gerçekten doğaüstü güçlere sahip olduğunu düşünmeye başlamıştır. - -Büyüdükten sonra ailesi tarafından Rusyanın başka bir bölgesine gönderilir ve burada manastırda eğitim almaya başlar. Fakat kehanetleri azalmadığı gibi artmaya da başlar. İlgileri yine üzerine çekmeyi başarır burada da. Öyle ki 1904 yılında Çar Romanov’un küçük oğlu Aleksi’nin hemofili olduğunu öğrenir ve çocuğu ancak kendisinin tedavi edebileceğini iddia eder. Yine bir vaazında 1. Dünya Savaşından ve yaklaşmakta olan Bolşevik devriminden bahseder. Tarih tabiiki de onun yanılmadığını bize gösterecektir. Artık saraya çok yakındır ve vaazlarında Aleksi’nin hastalığını kendisinin tedavi edebileceğini çariçe Aleksandrova’ya açıklar. Çariçe kendisini saraya çağırır ve böylelikle Petersburg ve Kremlin saraylarının kapıları Rasputin’e sonuna kadar açılmış olur. - -Kısaca hayatından bahsettikten sonra [Boney M. grubunun şarkısında](https://www.youtube.com/watch?v=kvDMlk3kSYg) daha çok geçen ve ölümünü (!) anlatan kısma gelmek istiyorum. Bu kısımdan sonra anlatılanlar bir miktar yoruma dayalı olmakla birlikte anlatılanlar arasında tam bir mutabakat yoktur. - -Rasputin, Prens Yusufov tarafından bir davete çağrılır, fakat Prens, Rasputin’i kendisi ile özel bir konuda görüşmek bahanesiyle davetten önce evine daha bütün misafirler gelmeden ayrı getirtir. Durum oldukça gariptir, Rasputin’i bahçe tarafında bodrum katında bir odaya indirirler fakat ikramda kusur yoktur. Siyanürle hazırlanan kurabiyeler ve yine siyanürlü şarap sunulur Rasputin’e. Merakla Prens’in ne anlatacağını bekleyen Rasputin, kurabiyeleri afiyetle yer ve hatta şaraptan da birkaç kadeh içer. Bir türlü konuya girmeyen ve lafı geveleyen Prens, Rasputin’e hiçbir şey olmadığını görünce telaşa kapılır, müsaade ister ve komployu hazırladığı ve yine evde başka bir odada onu bekleyen İngiliz ajanından yardım ister. İngiliz ona bir silah verir ve sessizce bu işi bitirmesini söyler. Prens silahı alır, odaya gider ve iki el ateş eder, başından ve boynundan yaralanan Rasputin yere yığılır. Komplocu Prens bu işi bitirdiğini zannederek yukarı çıkar ve diğer işbirlikçileri aşağıya çağırır. Fakat iki metrelik bu dev Sibiryalıyı öldürmek o kadarda kolay değildir. Prens ve komplocular odaya girdiklerinde Rasputin ayaktadır, ölmemiştir. Rasputin kendisini bahçeye atar ve kaçmaya başlar. Fakat katiller peşine düşerler ve Rasputin bahçe duvarını aşacakken arkasından ateş ederler ve durdururlar. Artık bu tehlikeli adamı öldürdüklerini düşünürler ve cesedini neva nehrine atarlar. Ceset birkaç gün sonra nehirden çıkarılır, otopsi yapılır. Otopsi raporuna göre Rasputin kurşunlardan değil ciğerine dolan sudan, yani boğularak ölmüştür. Onu öldürmek hiçte kolay olmamıştır anlaşılan. - -Burada bir parantez açmak istiyorum. Boğulan ve ciğerler patlayarak dışarı çıkan birinin sadece birkaç organının zarar görmüş olacağını düşünmek mantıksız. Hem cildi hem de diğer bütün hayati organları zarar görmüştür bu olaylar sonunda. Kendisini bulduklarını düşündükleri zaman teşhis etme konusunda emin olamamışlardır. Bu yüzden ben o anda dahi ölmediğini ve efsaneler aslını yaşatır kuralı gereğince hayatına bir süre daha devam ettiğini düşünüyorum. Kendisi aynı zamanda **rasPUTİN** ismine sahip olduğu ve Rusyanın en önde gelen şahsı ile isimleri benzediği için şarkıları son zamanlarda oldukça ön planda. Gerçi Putin başta oldu olalı bu şarkılar ön planda ama şu son 5–6 senedir bu şarkılar üzerinden Putin övmesine doyamadılar maalesef. Hatta [“Rasputin — Funk Overload”](https://www.youtube.com/watch?v=YgGzAKP_HuM) adlı videoda Boney M. grubunun yapmış olduğu şarkıya bir animasyon ile farklı bir hava katmışlar. Ayrıca ilgili videonun içinde Putin ile ilgili bir bonus bölüm de mevcut. Hem eğlenceli hem de remix tarzı bir video olmuş. Bu kısa yazımız maalesef bitti. - -Bu hikayeyi yazarken faydalandığım siteleri kaynakça gibi eklemek isterdim ama paralel evrende şu anda tam olarak 10 dk geçti ve benim daha önemli işlerim var. O yüzden sevgili (!) Putine bir selam çakıp aranızdan ayrılıyorum. - -NOT: Bu yazı daha önce şahsi medium.com adresimde yayımlanmıştır. Kişisel portfolyo oluşturmak adına şahsi sitemde yeniden yayımlama ihtiyacı hissettim. +--- +title: "Grigori Rasputin ve aynı isimli şarkı hk" +date: 2020-05-01 +tags: ["müzik", "rasputin", "konu dışı", "ilginç"] +author: "Wise" +draft: false +--- +Nerede doğduğunu bilmediğimiz Grigori Rasputin isimli bu arkadaşın çocukluk yılları daha çok Sibirya geçiyor. Mavi gözleri ve etkileyici mimikleri var. Daha küçük yaştan itibaren insanları etkilemeyi ve ilgi çekmeyi başaran bir yapısı mevcut. Hatta bir keresinde yaşı küçük olmasına rağmen babasının çiftliğinden çalınan bir atı kimin çaldığını kehanet yoluyla tahmin eder. Herkes (babası da dahil) Rasputin’e inanmamış olsa da sonradan hırsız kendisi gelip suçunu itiraf eder. Bu olaydan sonra ailesi ve bütün çevresi onun gerçekten doğaüstü güçlere sahip olduğunu düşünmeye başlamıştır. + +Büyüdükten sonra ailesi tarafından Rusyanın başka bir bölgesine gönderilir ve burada manastırda eğitim almaya başlar. Fakat kehanetleri azalmadığı gibi artmaya da başlar. İlgileri yine üzerine çekmeyi başarır burada da. Öyle ki 1904 yılında Çar Romanov’un küçük oğlu Aleksi’nin hemofili olduğunu öğrenir ve çocuğu ancak kendisinin tedavi edebileceğini iddia eder. Yine bir vaazında 1. Dünya Savaşından ve yaklaşmakta olan Bolşevik devriminden bahseder. Tarih tabiiki de onun yanılmadığını bize gösterecektir. Artık saraya çok yakındır ve vaazlarında Aleksi’nin hastalığını kendisinin tedavi edebileceğini çariçe Aleksandrova’ya açıklar. Çariçe kendisini saraya çağırır ve böylelikle Petersburg ve Kremlin saraylarının kapıları Rasputin’e sonuna kadar açılmış olur. + +Kısaca hayatından bahsettikten sonra [Boney M. grubunun şarkısında](https://www.youtube.com/watch?v=kvDMlk3kSYg) daha çok geçen ve ölümünü (!) anlatan kısma gelmek istiyorum. Bu kısımdan sonra anlatılanlar bir miktar yoruma dayalı olmakla birlikte anlatılanlar arasında tam bir mutabakat yoktur. + +Rasputin, Prens Yusufov tarafından bir davete çağrılır, fakat Prens, Rasputin’i kendisi ile özel bir konuda görüşmek bahanesiyle davetten önce evine daha bütün misafirler gelmeden ayrı getirtir. Durum oldukça gariptir, Rasputin’i bahçe tarafında bodrum katında bir odaya indirirler fakat ikramda kusur yoktur. Siyanürle hazırlanan kurabiyeler ve yine siyanürlü şarap sunulur Rasputin’e. Merakla Prens’in ne anlatacağını bekleyen Rasputin, kurabiyeleri afiyetle yer ve hatta şaraptan da birkaç kadeh içer. Bir türlü konuya girmeyen ve lafı geveleyen Prens, Rasputin’e hiçbir şey olmadığını görünce telaşa kapılır, müsaade ister ve komployu hazırladığı ve yine evde başka bir odada onu bekleyen İngiliz ajanından yardım ister. İngiliz ona bir silah verir ve sessizce bu işi bitirmesini söyler. Prens silahı alır, odaya gider ve iki el ateş eder, başından ve boynundan yaralanan Rasputin yere yığılır. Komplocu Prens bu işi bitirdiğini zannederek yukarı çıkar ve diğer işbirlikçileri aşağıya çağırır. Fakat iki metrelik bu dev Sibiryalıyı öldürmek o kadarda kolay değildir. Prens ve komplocular odaya girdiklerinde Rasputin ayaktadır, ölmemiştir. Rasputin kendisini bahçeye atar ve kaçmaya başlar. Fakat katiller peşine düşerler ve Rasputin bahçe duvarını aşacakken arkasından ateş ederler ve durdururlar. Artık bu tehlikeli adamı öldürdüklerini düşünürler ve cesedini neva nehrine atarlar. Ceset birkaç gün sonra nehirden çıkarılır, otopsi yapılır. Otopsi raporuna göre Rasputin kurşunlardan değil ciğerine dolan sudan, yani boğularak ölmüştür. Onu öldürmek hiçte kolay olmamıştır anlaşılan. + +Burada bir parantez açmak istiyorum. Boğulan ve ciğerler patlayarak dışarı çıkan birinin sadece birkaç organının zarar görmüş olacağını düşünmek mantıksız. Hem cildi hem de diğer bütün hayati organları zarar görmüştür bu olaylar sonunda. Kendisini bulduklarını düşündükleri zaman teşhis etme konusunda emin olamamışlardır. Bu yüzden ben o anda dahi ölmediğini ve efsaneler aslını yaşatır kuralı gereğince hayatına bir süre daha devam ettiğini düşünüyorum. Kendisi aynı zamanda **rasPUTİN** ismine sahip olduğu ve Rusyanın en önde gelen şahsı ile isimleri benzediği için şarkıları son zamanlarda oldukça ön planda. Gerçi Putin başta oldu olalı bu şarkılar ön planda ama şu son 5–6 senedir bu şarkılar üzerinden Putin övmesine doyamadılar maalesef. Hatta [“Rasputin — Funk Overload”](https://www.youtube.com/watch?v=YgGzAKP_HuM) adlı videoda Boney M. grubunun yapmış olduğu şarkıya bir animasyon ile farklı bir hava katmışlar. Ayrıca ilgili videonun içinde Putin ile ilgili bir bonus bölüm de mevcut. Hem eğlenceli hem de remix tarzı bir video olmuş. Bu kısa yazımız maalesef bitti. + +Bu hikayeyi yazarken faydalandığım siteleri kaynakça gibi eklemek isterdim ama paralel evrende şu anda tam olarak 10 dk geçti ve benim daha önemli işlerim var. O yüzden sevgili (!) Putine bir selam çakıp aranızdan ayrılıyorum. + +NOT: Bu yazı daha önce şahsi medium.com adresimde yayımlanmıştır. Kişisel portfolyo oluşturmak adına şahsi sitemde yeniden yayımlama ihtiyacı hissettim. diff --git a/content/post/maximum-kart-reklami.md b/content/post/maximum-kart-reklami.md index 43b0e0d1..1e65575d 100644 --- a/content/post/maximum-kart-reklami.md +++ b/content/post/maximum-kart-reklami.md @@ -1,27 +1,27 @@ ---- -title: "Maximum Kart reklamı Rubicon nehrini geçti mi?" -date: 2020-05-16 -tags: ["reklam", "maximum", "cem yılmaz", "konu dışı", "ilginç"] -author: "Wise" -draft: false -cover: - image: "/images/maximumkart/alesia-war-cover.jpeg" - hidden: false ---- -Maximum Kart’ın artık müze kartı olarak geçerli olmadığı şu günlerde “Zaten müze müze gezip de ne yapacağız, biz Cem Yılmaz izliyoruz o bize yetiyor” şeklinde düşünen arkadaşlar için bir içerik hazırladım. Bildiğiniz veya benim de uydurmuş olabileceğim üzere İş bankasının maximum kart departmının Cem Yılmaz ve diğer sanatçılar ile yapmış olduğu 4–6 reklamlık bir iş birliği (PR) anlaşması mevcuttu. Bu süreçte bankanın ve kartın kullanımını teşvik edecek ve aynı zamanda da Cem Yılmaz üzerinden bilinirliliğini artırıcı bir takım reklamlar çekildi ve basında yayımlandı. Bu reklamdan büyük bir çoğunluğu son kullanıcıya hitap eden ve direkt ürünün olduğu yerde (market, kafe v.b.) çekilmiş reklamlar olmasına rağmen içlerinden bir tanesi tamamen başka bir atmosferde çekilmişti. Sadece müze kart övmesi için bu kadar prodüksiyona ne gerek vardı diye düşünürken Cem Yılmazın böyle ilginç içerikleri çok sevdiği ve çok az kişinin anladığı ufak espiriler bıraktığı aklıma geldi. Mesela meşhur G.O.R.A filmindeki “evet evet tarafından” espirisinin bir dönem anlaşılmamış olması ve Cem Yılmazın bizatihi kendisi tarafından açıklanması sonucunda meşhur olması gibi. İşte ben de bugün sizlerle bu reklamı inceleyecek ve üzerine bir şeyler söyleyeceğim. - -{{< youtube weFr-uSNjHo >}} - -Öncelikle reklamın tümünde geçen replikler veya arka planların hepsi büyük özenle seçilmiş yerler. Hani bir savaş sahnesi canlandıralım diye yapılmış şeyler değil. Reklamın başladığı yer o dönem Galyalılara ait olan ve Vercingetorix tarafından yönetilen 80.000 kişi ile en büyük Galya şehri olan Alesia’dır. Yapılan savaş da şehirden ismini alan Alesia savaşıdır. Savaş M.Ö 52 yılında Sezar komutasındaki 12 lejyonla (30,000–60,000 kişi)’nin günümüzdeki Paris sınırları içerisinde kalan Alesia şehrini kuşatması sonucunda çıkıyor. Tüm Avrupayı neredeyse fetheden Roma İmparatorluğu bir türlü bu Galyalıları (Fransa civarlarında) yenemiyor. En sonunda direkt saldırmaya karar veriyorlar ama bilmiyorlar ki Galyalılar savunmada acayip iyiler. Gerçekten de beklenilen oluyor ve Galyalılar kaleye çekiliyor. Sezar ne yaptıysa kaleye yaklaşamıyor ve surları aşamıyor. Adamları açlık ile karşı karşıya bırakmış olmasına rağmen Galyalılar teslim olmuyor bir türlü. - -![Alesia Savaşı Günümüzde Olsaydı](/images/maximumkart/maximum-kart-afis.jpg) - -Videonun daha ilk saniyede gözüken sarımsı bayrak Galyalıların kullandığı renk olup tahminimce eski bayraklarından birisidir. Normalde bayrakları yine o renk olmak üzere bir kartal-kuş türünü barındıran bir bayraktır ama renk direkt bu. Truva atı olayı M.Ö 13. yy da geçen ve yine Paris civarlarında yapılan bir taktiktir. Yine o civarda yaşamış Akhalılar tarafından yapılan iş bu taktik bu yüzden “daha önce denendi olmaz” deyip geçiyor. Sonrasında ise Brütüs’e dönüp “sen dur” veya “sen de var ya” der gibi bakması ve mimikleri Sezar ile Brütüs arasındaki bıçaklama olayına bir gönderme. Maximus ismi direkt maximum karta bir atıf olmasının haricinde filmde bu neyin kafası diyen (o dönemki lider) Sezardan sonraki adama gönderme. Tam adı Marcus Maximus Aurelius Antoninus Augustus olan ve sezardan sonra hüküm süren bir lider. Sonunda geçen “Biz buraya Sezarı övmeye değil gömmeye geldik.” sözü de orada beyaz kafası gözüken Marcus Antonius’a bir göndermedir. Kendisi Sezar’a suiskastten yargılanmış birisidir. Bence bu haliyle (benim yakalayabildiğim) reklam efsane kurgulanmış. Son olarak ilk kredi kartının çıkış tarihi ile Savaş tarihi olan M.Ö 52 arasında yaklaşık 2.000 Yıl olması da bir tesadüf değildir diye düşünüyorum. - -Rubicon nehrini geçmek özdeyişi adını İtalya’da bulunan rubicon nehrinden alır. Roma Cumhuriyeti döneminde komutanlar askeri güçleri ve kimlikleri ile başkente giremeyeceği ve demokrasiye aykırı bir eylem olarak görüldüğü için Roma şehir sınırlarından biri olan Rubicon nehrini geçmek askerlere yasaklanmıştı. Roma’yı ele geçirmek isteyen komutanlar ilk eylem olarak bulundukları karargahtan çıkarak Rubicon nehrini geçer ve bu artık geri dönüşü olmayan bu yola girerlerdi. Bu öyle bir yoldu ki artık kararlarından vazgeçseler bile cezalandırılacaklardır. O yüzden Rubicon’u geçmeyi çok iyi hesaplamak, çok iyi düşünmek gerek. Maximum Kart Cem Yılmaz ile böyle bir reklam yaparak bence kitleleri etkileyecek bir şey yapmak istemiş olsa da kimsenin farketmeyeceği ama bence çok güzel bir reklama imza attılar. - -Bütün bu anlatımlardan sonra “bize maximum kart tarafından böyle bir şey söylenmedi” veya “kafandan uyduruyorsun bütün bunları” diyecekseniz sizi bonus sahneye alayım. - -{{< youtube e6AbhhSOjEE >}} - -NOT: Bu yazı daha önce şahsi medium.com adresimde yayımlanmıştır. Kişisel portfolyo oluşturmak adına şahsi sitemde yeniden yayımlama ihtiyacı hissettim. +--- +title: "Maximum Kart reklamı Rubicon nehrini geçti mi?" +date: 2020-05-16 +tags: ["reklam", "maximum", "cem yılmaz", "konu dışı", "ilginç"] +author: "Wise" +draft: false +cover: + image: "/images/maximumkart/alesia-war-cover.jpeg" + hidden: false +--- +Maximum Kart’ın artık müze kartı olarak geçerli olmadığı şu günlerde “Zaten müze müze gezip de ne yapacağız, biz Cem Yılmaz izliyoruz o bize yetiyor” şeklinde düşünen arkadaşlar için bir içerik hazırladım. Bildiğiniz veya benim de uydurmuş olabileceğim üzere İş bankasının maximum kart departmının Cem Yılmaz ve diğer sanatçılar ile yapmış olduğu 4–6 reklamlık bir iş birliği (PR) anlaşması mevcuttu. Bu süreçte bankanın ve kartın kullanımını teşvik edecek ve aynı zamanda da Cem Yılmaz üzerinden bilinirliliğini artırıcı bir takım reklamlar çekildi ve basında yayımlandı. Bu reklamdan büyük bir çoğunluğu son kullanıcıya hitap eden ve direkt ürünün olduğu yerde (market, kafe v.b.) çekilmiş reklamlar olmasına rağmen içlerinden bir tanesi tamamen başka bir atmosferde çekilmişti. Sadece müze kart övmesi için bu kadar prodüksiyona ne gerek vardı diye düşünürken Cem Yılmazın böyle ilginç içerikleri çok sevdiği ve çok az kişinin anladığı ufak espiriler bıraktığı aklıma geldi. Mesela meşhur G.O.R.A filmindeki “evet evet tarafından” espirisinin bir dönem anlaşılmamış olması ve Cem Yılmazın bizatihi kendisi tarafından açıklanması sonucunda meşhur olması gibi. İşte ben de bugün sizlerle bu reklamı inceleyecek ve üzerine bir şeyler söyleyeceğim. + +{{< youtube weFr-uSNjHo >}} + +Öncelikle reklamın tümünde geçen replikler veya arka planların hepsi büyük özenle seçilmiş yerler. Hani bir savaş sahnesi canlandıralım diye yapılmış şeyler değil. Reklamın başladığı yer o dönem Galyalılara ait olan ve Vercingetorix tarafından yönetilen 80.000 kişi ile en büyük Galya şehri olan Alesia’dır. Yapılan savaş da şehirden ismini alan Alesia savaşıdır. Savaş M.Ö 52 yılında Sezar komutasındaki 12 lejyonla (30,000–60,000 kişi)’nin günümüzdeki Paris sınırları içerisinde kalan Alesia şehrini kuşatması sonucunda çıkıyor. Tüm Avrupayı neredeyse fetheden Roma İmparatorluğu bir türlü bu Galyalıları (Fransa civarlarında) yenemiyor. En sonunda direkt saldırmaya karar veriyorlar ama bilmiyorlar ki Galyalılar savunmada acayip iyiler. Gerçekten de beklenilen oluyor ve Galyalılar kaleye çekiliyor. Sezar ne yaptıysa kaleye yaklaşamıyor ve surları aşamıyor. Adamları açlık ile karşı karşıya bırakmış olmasına rağmen Galyalılar teslim olmuyor bir türlü. + +![Alesia Savaşı Günümüzde Olsaydı](/images/maximumkart/maximum-kart-afis.jpg) + +Videonun daha ilk saniyede gözüken sarımsı bayrak Galyalıların kullandığı renk olup tahminimce eski bayraklarından birisidir. Normalde bayrakları yine o renk olmak üzere bir kartal-kuş türünü barındıran bir bayraktır ama renk direkt bu. Truva atı olayı M.Ö 13. yy da geçen ve yine Paris civarlarında yapılan bir taktiktir. Yine o civarda yaşamış Akhalılar tarafından yapılan iş bu taktik bu yüzden “daha önce denendi olmaz” deyip geçiyor. Sonrasında ise Brütüs’e dönüp “sen dur” veya “sen de var ya” der gibi bakması ve mimikleri Sezar ile Brütüs arasındaki bıçaklama olayına bir gönderme. Maximus ismi direkt maximum karta bir atıf olmasının haricinde filmde bu neyin kafası diyen (o dönemki lider) Sezardan sonraki adama gönderme. Tam adı Marcus Maximus Aurelius Antoninus Augustus olan ve sezardan sonra hüküm süren bir lider. Sonunda geçen “Biz buraya Sezarı övmeye değil gömmeye geldik.” sözü de orada beyaz kafası gözüken Marcus Antonius’a bir göndermedir. Kendisi Sezar’a suiskastten yargılanmış birisidir. Bence bu haliyle (benim yakalayabildiğim) reklam efsane kurgulanmış. Son olarak ilk kredi kartının çıkış tarihi ile Savaş tarihi olan M.Ö 52 arasında yaklaşık 2.000 Yıl olması da bir tesadüf değildir diye düşünüyorum. + +Rubicon nehrini geçmek özdeyişi adını İtalya’da bulunan rubicon nehrinden alır. Roma Cumhuriyeti döneminde komutanlar askeri güçleri ve kimlikleri ile başkente giremeyeceği ve demokrasiye aykırı bir eylem olarak görüldüğü için Roma şehir sınırlarından biri olan Rubicon nehrini geçmek askerlere yasaklanmıştı. Roma’yı ele geçirmek isteyen komutanlar ilk eylem olarak bulundukları karargahtan çıkarak Rubicon nehrini geçer ve bu artık geri dönüşü olmayan bu yola girerlerdi. Bu öyle bir yoldu ki artık kararlarından vazgeçseler bile cezalandırılacaklardır. O yüzden Rubicon’u geçmeyi çok iyi hesaplamak, çok iyi düşünmek gerek. Maximum Kart Cem Yılmaz ile böyle bir reklam yaparak bence kitleleri etkileyecek bir şey yapmak istemiş olsa da kimsenin farketmeyeceği ama bence çok güzel bir reklama imza attılar. + +Bütün bu anlatımlardan sonra “bize maximum kart tarafından böyle bir şey söylenmedi” veya “kafandan uyduruyorsun bütün bunları” diyecekseniz sizi bonus sahneye alayım. + +{{< youtube e6AbhhSOjEE >}} + +NOT: Bu yazı daha önce şahsi medium.com adresimde yayımlanmıştır. Kişisel portfolyo oluşturmak adına şahsi sitemde yeniden yayımlama ihtiyacı hissettim. diff --git a/content/post/modern-kriptografi-star-wars.md b/content/post/modern-kriptografi-star-wars.md index 71c1ad4a..f55ae320 100644 --- a/content/post/modern-kriptografi-star-wars.md +++ b/content/post/modern-kriptografi-star-wars.md @@ -1,28 +1,28 @@ ---- -title: "Modern kriptografi yöntemlerinin Star Wars filmi ile ilişkisi" -date: 2020-04-28 -tags: ["kriptografi", "star wars", "security", "ssl" ,"tls"] -author: "Wise" -draft: false ---- -> Uzun uzun bir zaman önce (!) pek de uzak olmayan bir galakside yaşayan insanlar internet üzerinden yapmış oldukları işlemlerin daha güvenli bir temele oturması ve bu iletişimin tarafları dışındaki üçüncü kişilerin bu iletişimi dinleyememesi ve hakkında bilgi sahibi olamaması için bir takım şifreleme yöntemleri geliştirmeye karar verirler. [INTRO](https://starwarsintrocreator.kassellabs.io/#!/BM5xzF-d7ZTSDYuCtJC9) - -Daha önceden üniversitelerin matematik ve bilgisayar programcılığı bölümlerinde yapılmış akademik çalışmaların ötesine geçememiş olan şifreleme (cryptography) alanı artık bireylerin iyiliği için kullanılacaktı. Bu ilke imza atacak ilk kişilerin arkadaş olmasının dışında onları birleştiren asıl şey Star Wars’ın orijinal üçlemesini çocuklukları döneminde birlikte izlemiş ve etkinlenmiş olmalarıdır. 1977 Yılında orijinal üçlemenin ilk, tarihsel sıralamaya göre ise dördüncü film olan [Star Wars A New Hope](https://en.wikipedia.org/wiki/Star_Wars_(film)) vizyona girmiş ve tüm çevreler tarafından beğeniyle izlenmişti. İlk filmin vizyona girişinden sonraki 3. ve 6. senelerde serinin beşinci ve altıncı filmleri olan [The Empire Strikes Back](https://en.wikipedia.org/wiki/The_Empire_Strikes_Back) ve [Return of the Jedi](https://en.wikipedia.org/wiki/Return_of_the_Jedi) de peş peşe vizyona girmiş ve seyircisinin filmden beklentisini ve serinin devamına olan isteğini artırmıştır. Serinin o dönemki yönetmeni George Lucas izleyenleri daha iyi bir üçlemeye hazırlamak adına orijinal üçlemenin üçüncü filminin vizyona girdiği tarih olan 1983 yılından 1999 yılına kadar seriye yeni film çıkarmamış ve teknolojik imkanların gelişmesini beklemiştir. Yani tarihsel üçleme efsanesinin ve de modern kriptografinin bence başladığı yıl olan 1999 yılına gelinene kadar. 90'lı yıllar kendilerini Cypherpunks olarak adlandıran ve açık kaynak kodunu yücelten, gizlilik ve bireyin anonimlik hakkı üzerinde bir manifesto yayımlayan, bilgisayar ve teknoloji ile birlikte büyümüş bir neslin dönemiydi. İnternetin ülkemize gelişi ve tüm dünyadaki internet ağının gelişmesi ile birlikte 2000'li yıllara girmeye yaklaştığımız dönemlerde kişi başına düşen bilgisayar sayısı oranı artmış ve her eve olmasa da birçok haneye geniş bant internet hizmeti ulaşmış bulunmaktaydı. İşte ülkemizde internet yeni yeni kabul görmeye ve kullanılmaya başlandığı dönemlerde yurt dışında bir arkadaş topluluğu World Wide Web (WWW)’in eksik taraflarından biri olan şifreleme ve gizlilik üzerine odaklanmaya başlamıştı bile. - -Basit anlatımıyla internet üzerinde bir websitesi barındırmamıza ve dünya üzerindeki herhangi bir bilgisayarın bu web sayfasına erişebilmesine imkan tanıyan bu servis temelde güzel olmasına rağmen çok büyük bir dezavantajı vardı. Bu dezavantaj bağlanmış olduğunuz internet sitesi ile aranızdaki bağlantının herhangi bir şekilde şifrelenmemesi, güvenli olmaması ve dahili/harici üçüncü kişiler tarafından bu iletişimin izlenebilir, değiştirilebilir ve dahi engellenebilir olmasıdır. Eskiden bir internet sitesine girdiğiniz zaman adres çubuğunda bir kilit simgesi ve aşağıda gördüğünüz gibi “Connection is secure” veya “Connection is not private” gibi bir bağlantının güvenli /güvensiz olduğunu düşündürecek bir bildirim yoktu. Çünkü o yıllarda bir internet sitesine üye olurken veya mail gönderirken iletişimin izlenebileceği veya bunu kötü amaçlar için kullanılabileceği henüz düşünülmemişti. - -||| -|:---:|:---:| -| ![Bağlantı Güvenli Bildirimi Chrome](/images/starwars-kriptografi/connection-is-secure.jpg) | ![Bağlantı Güvenli Değil Bildirimi Chrome](/images/starwars-kriptografi/not-private-notification.png) | - -Konunun girişine eklenmiş olan videoda 1977 yapımı Star Wars New Hope filminde (bunca yıldan sonra spoiler denemez artık) Galaktik İmparatorluk tarafından bütün galaksiyi yok edebilecek güçte ve devasa ölçekte bir ölüm yıldızı yapıldığının haberi alınır. Bu haberin alınması üzerine kendilerine Rebellion (isyancı) diyen bir grup bu ölçekte ve güçte bir geminin normal gemi savaşları ile yok edilemeyeceğini anlamış ve bu planları çalıp geminin zayıf noktalarını incelemeye karar vermişlerdir. Orijinal üçlemenin ilk filmi olmasına rağmen tarihsel olarak 4'ncü film olması nedeniyle filmin başlangıcında bu planların çalındığını fakat henüz inceleme imkanı bulunamadan planları çalan uzay gemisinin imparatorluk kuvvetleri ve meşhur Dart Vader tarafından kovalandığını görüyoruz. Kovalamacanın sonuna doğru ellerindeki planları güvenli bir şekilde isyan kuvvetlerinin ana karargahına göndermeleri gerektiğini fakat imparatorluk kuvvetleri tarafından takip edilirken bunun çok zor olacağını anlayan Prenses Leia kendisince en güvenli gördüğü yöntemi kullanarak R2-D2 sınıfı bir robotun belleğine planları yükler ve filmimiz burada başlar. Videonun başlangıcında Dart Vader ve imparatorluk kuvvetleri tarafından geminin tamamı aranmasına rağmen Ölüm Yıldızının çalınmış planları bir türlü bulunamaz. Her ne kadar asilerden biri olduğu bilinse de (henüz Dart Vader tarafından ispatlanamamış) Prenses Leia diplomatik bir resmi görevde olduğunu söylemiş ve kendilerine böyle bir verinin gelmediğini iddia etmiştir. Yapılan incelemede gemiden böyle bir verinin aktarıldığını gösteren bir bilgiye de rastlanamamış olması sevgili Vader’ımızı çokça kızdırmıştır. - -Günümüzden 21 sene önce vizyona girmiş olan [The Phantom Menace](https://en.wikipedia.org/wiki/Star_Wars:_Episode_I_–_The_Phantom_Menace) filmi her ne kadar modern şifrelemeyi doğrudan etkilememiş olsa da bu bir grup kişiye yıllar önce izlemiş ve beğenmiş oldukları orijinal üçlemenin ilk filmini ve bence ilk sahnesini hatırlamalarına neden oldu. O dönem gelişmekte olan gizlilik, anonimlik ve güvenlik düşünceleri neticesinde filmi izledikten sonra eski günleri yad etmek ve düşüncelerini paylaşmak için bir kafede bir araya geldiler. Genel arkadaş muhabbetinden ve havadan sudan konuşulduktan sonra aralarından biri konuşmanın ve bence tarihin de seyrini değiştiren şu soruyu sordu: - -> How can I keep communication private and secure when sending Death Star’s stolen blueprints ? - -Arkadaş grubu önce bir sessizliğe büründü ve soruyu soran kişi aynı ses tonuyla soruyu tekrarladı ve bu sefer sonuna **“But without using R2-D2 or any kind of Droid :D”** ekledi. Grupta yükselen gülüşmelerin ve filmle ilgili ardı ardına söylenen repliklerin ardından gruptaki kişiler birbirlerine bakarak bu soruna nasıl bir çözüm bulabileceklerini veya bunu kimin yapabileceğini düşünmeye koyuldular. Çok geçmeden bu soruya cevap bulabilecek kişilerin aslında bu sorunu ilk farkeden kişiler yani grup arkadaşları olduğunu anladılar. Hepsi ülkelerinde önemli üniversitelerden mezun olmuş ve alanlarında uzmanlaşmak, kendilerini geliştirmek için akademik kariyerlerine devam etmişlerdi. O dönem için böyle bir projenin yapılması için gerekli tüm matematiksel sorunların çözümü ile bilgisayarda yapılması gereken kodlamanın altından grup olarak kalkabileceklerini düşündüler. Grup olarak önce kullanıcıdan kaynaklı çözüm yöntemleri ile başlayıp ardından sunucular ve genele inen bir proje planı yaptılar. İlk olarak PGP (Pretty Good Privacy) adı ile anılan ve ilk dökümanlarının yayımlanmasının üzerinden neredeyse 8 sene geçmiş bir veri şifreleme-çözme yöntemi üzerinde durdular. Bu yöntemin (günümüzde nispeten daha güvenli olan) mail alışverişi sırasında kullanılmasının taraflar arasındaki gizliliği artıracağını düşündüler. Böylece kendilerine sormuş oldukları sorunun “güvenlik” kısmını irdelemeye başladılar ve bu başlangıç onları hiç tahmin edemeyecekleri yerlere ve kişilere götürdü. Onlar seçimini kırmızı hapı almaktan yana kullandılar. Böylece bilgisayardaki harikalar diyarının ve tavşan deliğinin ne kadar derin olduğunu tüm insanlara gösterme imkanı buldular. Yazı her ne kadar Star Wars filmi ile ilişkisi üzerinden devam etmiş olsa da Matrix filminin de aynı dönemde vizyona girdiği düşünüldüğünde böyle bir baş yapıttan etkilenilmediğini düşünmek yanlış olur. - -Eğer yazının bu kısmına kadar gelmeyi başardıysanız merakınızın sizi bir yerlere sürüklediğini, siz istediğiniz ve ben kendimde yazma kuvveti bulduğum sürece bu tavşan deliğinin ne kadar derin olabileceğini birlikte keşfedeceğimizi anlamışsınızdır. Eğer her yerde anlatılan alışılmış hikayelerin ve kalıplaşmış kabullerin ötesinde bilgisayar ve insan arasındaki ilişkinin nasıl işlediğini, arka planda neler olduğunu öğrenmek istiyorsanız beni Twitter'dan ve şu an bulunduğunuz medium sitesinden takip edebilirsiniz. Sizlere şimdilik “her x günde veya x haftada bir yazı” şeklinde bir söz veremiyorum. Sizlere karşı verebileceğim tek söz benden bir şey beklemezseniz sizi bu konuda hayal kırıklığına da uğratamayacağım olacaktır. Yazı bitti. After credit sahnesini izlemek isteyenler için videomuza geçiyoruz. - -NOT: Bu yazı daha önce şahsi medium.com adresimde yayımlanmıştır. Kişisel portfolyo oluşturmak adına şahsi sitemde yeniden yayımlama ihtiyacı hissettim. +--- +title: "Modern kriptografi yöntemlerinin Star Wars filmi ile ilişkisi" +date: 2020-04-28 +tags: ["kriptografi", "star wars", "security", "ssl" ,"tls"] +author: "Wise" +draft: false +--- +> Uzun uzun bir zaman önce (!) pek de uzak olmayan bir galakside yaşayan insanlar internet üzerinden yapmış oldukları işlemlerin daha güvenli bir temele oturması ve bu iletişimin tarafları dışındaki üçüncü kişilerin bu iletişimi dinleyememesi ve hakkında bilgi sahibi olamaması için bir takım şifreleme yöntemleri geliştirmeye karar verirler. [INTRO](https://starwarsintrocreator.kassellabs.io/#!/BM5xzF-d7ZTSDYuCtJC9) + +Daha önceden üniversitelerin matematik ve bilgisayar programcılığı bölümlerinde yapılmış akademik çalışmaların ötesine geçememiş olan şifreleme (cryptography) alanı artık bireylerin iyiliği için kullanılacaktı. Bu ilke imza atacak ilk kişilerin arkadaş olmasının dışında onları birleştiren asıl şey Star Wars’ın orijinal üçlemesini çocuklukları döneminde birlikte izlemiş ve etkinlenmiş olmalarıdır. 1977 Yılında orijinal üçlemenin ilk, tarihsel sıralamaya göre ise dördüncü film olan [Star Wars A New Hope](https://en.wikipedia.org/wiki/Star_Wars_(film)) vizyona girmiş ve tüm çevreler tarafından beğeniyle izlenmişti. İlk filmin vizyona girişinden sonraki 3. ve 6. senelerde serinin beşinci ve altıncı filmleri olan [The Empire Strikes Back](https://en.wikipedia.org/wiki/The_Empire_Strikes_Back) ve [Return of the Jedi](https://en.wikipedia.org/wiki/Return_of_the_Jedi) de peş peşe vizyona girmiş ve seyircisinin filmden beklentisini ve serinin devamına olan isteğini artırmıştır. Serinin o dönemki yönetmeni George Lucas izleyenleri daha iyi bir üçlemeye hazırlamak adına orijinal üçlemenin üçüncü filminin vizyona girdiği tarih olan 1983 yılından 1999 yılına kadar seriye yeni film çıkarmamış ve teknolojik imkanların gelişmesini beklemiştir. Yani tarihsel üçleme efsanesinin ve de modern kriptografinin bence başladığı yıl olan 1999 yılına gelinene kadar. 90'lı yıllar kendilerini Cypherpunks olarak adlandıran ve açık kaynak kodunu yücelten, gizlilik ve bireyin anonimlik hakkı üzerinde bir manifesto yayımlayan, bilgisayar ve teknoloji ile birlikte büyümüş bir neslin dönemiydi. İnternetin ülkemize gelişi ve tüm dünyadaki internet ağının gelişmesi ile birlikte 2000'li yıllara girmeye yaklaştığımız dönemlerde kişi başına düşen bilgisayar sayısı oranı artmış ve her eve olmasa da birçok haneye geniş bant internet hizmeti ulaşmış bulunmaktaydı. İşte ülkemizde internet yeni yeni kabul görmeye ve kullanılmaya başlandığı dönemlerde yurt dışında bir arkadaş topluluğu World Wide Web (WWW)’in eksik taraflarından biri olan şifreleme ve gizlilik üzerine odaklanmaya başlamıştı bile. + +Basit anlatımıyla internet üzerinde bir websitesi barındırmamıza ve dünya üzerindeki herhangi bir bilgisayarın bu web sayfasına erişebilmesine imkan tanıyan bu servis temelde güzel olmasına rağmen çok büyük bir dezavantajı vardı. Bu dezavantaj bağlanmış olduğunuz internet sitesi ile aranızdaki bağlantının herhangi bir şekilde şifrelenmemesi, güvenli olmaması ve dahili/harici üçüncü kişiler tarafından bu iletişimin izlenebilir, değiştirilebilir ve dahi engellenebilir olmasıdır. Eskiden bir internet sitesine girdiğiniz zaman adres çubuğunda bir kilit simgesi ve aşağıda gördüğünüz gibi “Connection is secure” veya “Connection is not private” gibi bir bağlantının güvenli /güvensiz olduğunu düşündürecek bir bildirim yoktu. Çünkü o yıllarda bir internet sitesine üye olurken veya mail gönderirken iletişimin izlenebileceği veya bunu kötü amaçlar için kullanılabileceği henüz düşünülmemişti. + +||| +|:---:|:---:| +| ![Bağlantı Güvenli Bildirimi Chrome](/images/starwars-kriptografi/connection-is-secure.jpg) | ![Bağlantı Güvenli Değil Bildirimi Chrome](/images/starwars-kriptografi/not-private-notification.png) | + +Konunun girişine eklenmiş olan videoda 1977 yapımı Star Wars New Hope filminde (bunca yıldan sonra spoiler denemez artık) Galaktik İmparatorluk tarafından bütün galaksiyi yok edebilecek güçte ve devasa ölçekte bir ölüm yıldızı yapıldığının haberi alınır. Bu haberin alınması üzerine kendilerine Rebellion (isyancı) diyen bir grup bu ölçekte ve güçte bir geminin normal gemi savaşları ile yok edilemeyeceğini anlamış ve bu planları çalıp geminin zayıf noktalarını incelemeye karar vermişlerdir. Orijinal üçlemenin ilk filmi olmasına rağmen tarihsel olarak 4'ncü film olması nedeniyle filmin başlangıcında bu planların çalındığını fakat henüz inceleme imkanı bulunamadan planları çalan uzay gemisinin imparatorluk kuvvetleri ve meşhur Dart Vader tarafından kovalandığını görüyoruz. Kovalamacanın sonuna doğru ellerindeki planları güvenli bir şekilde isyan kuvvetlerinin ana karargahına göndermeleri gerektiğini fakat imparatorluk kuvvetleri tarafından takip edilirken bunun çok zor olacağını anlayan Prenses Leia kendisince en güvenli gördüğü yöntemi kullanarak R2-D2 sınıfı bir robotun belleğine planları yükler ve filmimiz burada başlar. Videonun başlangıcında Dart Vader ve imparatorluk kuvvetleri tarafından geminin tamamı aranmasına rağmen Ölüm Yıldızının çalınmış planları bir türlü bulunamaz. Her ne kadar asilerden biri olduğu bilinse de (henüz Dart Vader tarafından ispatlanamamış) Prenses Leia diplomatik bir resmi görevde olduğunu söylemiş ve kendilerine böyle bir verinin gelmediğini iddia etmiştir. Yapılan incelemede gemiden böyle bir verinin aktarıldığını gösteren bir bilgiye de rastlanamamış olması sevgili Vader’ımızı çokça kızdırmıştır. + +Günümüzden 21 sene önce vizyona girmiş olan [The Phantom Menace](https://en.wikipedia.org/wiki/Star_Wars:_Episode_I_–_The_Phantom_Menace) filmi her ne kadar modern şifrelemeyi doğrudan etkilememiş olsa da bu bir grup kişiye yıllar önce izlemiş ve beğenmiş oldukları orijinal üçlemenin ilk filmini ve bence ilk sahnesini hatırlamalarına neden oldu. O dönem gelişmekte olan gizlilik, anonimlik ve güvenlik düşünceleri neticesinde filmi izledikten sonra eski günleri yad etmek ve düşüncelerini paylaşmak için bir kafede bir araya geldiler. Genel arkadaş muhabbetinden ve havadan sudan konuşulduktan sonra aralarından biri konuşmanın ve bence tarihin de seyrini değiştiren şu soruyu sordu: + +> How can I keep communication private and secure when sending Death Star’s stolen blueprints ? + +Arkadaş grubu önce bir sessizliğe büründü ve soruyu soran kişi aynı ses tonuyla soruyu tekrarladı ve bu sefer sonuna **“But without using R2-D2 or any kind of Droid :D”** ekledi. Grupta yükselen gülüşmelerin ve filmle ilgili ardı ardına söylenen repliklerin ardından gruptaki kişiler birbirlerine bakarak bu soruna nasıl bir çözüm bulabileceklerini veya bunu kimin yapabileceğini düşünmeye koyuldular. Çok geçmeden bu soruya cevap bulabilecek kişilerin aslında bu sorunu ilk farkeden kişiler yani grup arkadaşları olduğunu anladılar. Hepsi ülkelerinde önemli üniversitelerden mezun olmuş ve alanlarında uzmanlaşmak, kendilerini geliştirmek için akademik kariyerlerine devam etmişlerdi. O dönem için böyle bir projenin yapılması için gerekli tüm matematiksel sorunların çözümü ile bilgisayarda yapılması gereken kodlamanın altından grup olarak kalkabileceklerini düşündüler. Grup olarak önce kullanıcıdan kaynaklı çözüm yöntemleri ile başlayıp ardından sunucular ve genele inen bir proje planı yaptılar. İlk olarak PGP (Pretty Good Privacy) adı ile anılan ve ilk dökümanlarının yayımlanmasının üzerinden neredeyse 8 sene geçmiş bir veri şifreleme-çözme yöntemi üzerinde durdular. Bu yöntemin (günümüzde nispeten daha güvenli olan) mail alışverişi sırasında kullanılmasının taraflar arasındaki gizliliği artıracağını düşündüler. Böylece kendilerine sormuş oldukları sorunun “güvenlik” kısmını irdelemeye başladılar ve bu başlangıç onları hiç tahmin edemeyecekleri yerlere ve kişilere götürdü. Onlar seçimini kırmızı hapı almaktan yana kullandılar. Böylece bilgisayardaki harikalar diyarının ve tavşan deliğinin ne kadar derin olduğunu tüm insanlara gösterme imkanı buldular. Yazı her ne kadar Star Wars filmi ile ilişkisi üzerinden devam etmiş olsa da Matrix filminin de aynı dönemde vizyona girdiği düşünüldüğünde böyle bir baş yapıttan etkilenilmediğini düşünmek yanlış olur. + +Eğer yazının bu kısmına kadar gelmeyi başardıysanız merakınızın sizi bir yerlere sürüklediğini, siz istediğiniz ve ben kendimde yazma kuvveti bulduğum sürece bu tavşan deliğinin ne kadar derin olabileceğini birlikte keşfedeceğimizi anlamışsınızdır. Eğer her yerde anlatılan alışılmış hikayelerin ve kalıplaşmış kabullerin ötesinde bilgisayar ve insan arasındaki ilişkinin nasıl işlediğini, arka planda neler olduğunu öğrenmek istiyorsanız beni Twitter'dan ve şu an bulunduğunuz medium sitesinden takip edebilirsiniz. Sizlere şimdilik “her x günde veya x haftada bir yazı” şeklinde bir söz veremiyorum. Sizlere karşı verebileceğim tek söz benden bir şey beklemezseniz sizi bu konuda hayal kırıklığına da uğratamayacağım olacaktır. Yazı bitti. After credit sahnesini izlemek isteyenler için videomuza geçiyoruz. + +NOT: Bu yazı daha önce şahsi medium.com adresimde yayımlanmıştır. Kişisel portfolyo oluşturmak adına şahsi sitemde yeniden yayımlama ihtiyacı hissettim. diff --git a/content/post/openvpn-full-anlatim.de.md b/content/post/openvpn-full-anlatim.de.md index 296c5aa2..f426a093 100644 --- a/content/post/openvpn-full-anlatim.de.md +++ b/content/post/openvpn-full-anlatim.de.md @@ -1,139 +1,139 @@ ---- -title: "Eingehender OpenVPN-Test" -date: 2022-03-27 -tags: ["linux", "ssl", "security", "ecc", "elliptic curve", "openvpn", "tls", "aes"] -author: "Wise" -draft: false ---- -# Einführung und Zusammenfassung - -Heute werden wir OpenVPN, meiner Meinung nach eine der wichtigsten Software der letzten Zeit, ausführlich überprüfen. In diesem Test werden wir zuerst darüber sprechen, wofür OpenVPN verwendet wird. Dann untersuchen wir, was wir zum Ausführen des Programms benötigen und was vor dem ersten Ausführen zu tun ist. Abschließend werde ich versuchen zu erklären, was vom ersten Moment des Verbindungsaufbaus bis zum letzten Schritt, wenn die Daten entschlüsselt werden, im Hintergrund vor sich geht. Daher schätze ich, dass unser Artikel aus 3 Teilen und gegebenenfalls einem Frage-Antwort-Abschnitt bestehen wird. Jetzt schnallen wir uns an und machen einen Ausflug in die tiefe und düstere Welt des Internets. - -## Was ist OpenVPN und wofür wird es verwendet? - -Heutzutage gibt es fast kein Geschäft, das nicht online erledigt werden kann. Sogar unsere Arbeit, die normalerweise nicht online ist, hat sich aufgrund der Pandemie und der neuen Normalität auf die Arbeit von zu Hause aus entwickelt. Es gab jedoch große Probleme, sowohl weil es eine Arbeitsmethode ist, an die wir nicht gewöhnt sind, als auch weil unsere Leute nicht sehr gut mit Technologie umgehen können. Bevor klar wurde, dass die Menschen sich von ihren Heimcomputern mit ihren Bürocomputern verbinden mussten, kamen einige Unternehmen auf frivole Ideen, wie zum Beispiel, Bürocomputer zu den Häusern der Mitarbeiter zu schicken. Sie haben sehr gut verstanden, wie falsch das war, aus dem Feedback, das sie in kurzer Zeit erhalten haben. Kurz gesagt, es wurde endlich akzeptiert, dass elektronische Geräte im Büro bleiben und irgendwie eine sichere und nachhaltige Verbindung aus der Ferne hergestellt werden sollte. Natürlich befanden sich Institutionen auch schon früher in solchen Nöten, aber eine solche Großsituation kam damals nicht in Frage. Vor der Pandemie wurden verschiedene Protokolle wie PPTP, L2TP, IPSec, IKev2, SSTP und schließlich OpenVPN verwendet. Dies sind normalerweise Abkürzungen für bestimmte lange und ausgefallene Wörter, und ihre grundlegende Logik besteht darin, zwei oder mehr Geräte zu verbinden und sie so zu verhalten, als ob sie sich im selben Netzwerk befinden. Ich werde nicht viel sagen, da Protokolle vor OpenVPN gewisse Schwächen, Langsamkeit und technische Schwierigkeiten bei der Implementierung mit sich brachten. OpenVPN ist der Name des Protokolls und Programms, das es mindestens 2 Geräten in der Rolle von Server und Client ermöglicht, sich miteinander zu verbinden, und zwar auf eine Weise, die Industriestandards entspricht. Ich verwende ein Remote-Desktop-Programm. Ich höre Sie anscheinend sagen, was die Notwendigkeit dafür ist. Leider müssen er und alle anderen Programme wie er grundsätzlich dieses Protokoll verwenden. Wenn Sie das Schildsymbol oder die Verbindungsdetails in TeamViewer, einem der bekanntesten, drücken, können Sie das OpenVPN-Protokoll sehen. - -## Was brauchen wir, um eine OpenVPN-Verbindung aufzubauen? - -Zunächst muss OpenVPN sowohl auf der Server- als auch auf der Clientseite (dem zu verbindenden Gerät) installiert werden. Dann sollte eine Einstellungsdatei (Konfigurationsdatei) bearbeitet werden, die die Bedingungen zeigt, unter denen die Geräte kommunizieren. Das Hauptereignis ist, dass diese Konfigurationsdatei vom Client generiert und verwendet wird. Diese Konfigurationsdatei ist unterteilt in server_config, die vom Server verwendet wird, und client_config, die vom Client verwendet wird. - -### Die vom Server verwaltete Einstellungsdatei enthält die folgenden Einträge - -- `Port 1194` gibt an, welcher Port eine Verbindungsanfrage zum Herstellen der OpenVPN-Verbindung erhält. -- `proto tcp` Verbindung über TCP oder UDP möglich. Einstellungseintrag zur Auswahl eingetragen. -- `dev tun` TAP- oder TUN-Schnittstelle kann verwendet werden. Dies sind virtuelle Schnittstellen. TAP-Schicht 2 stellt eine Verbindung her, während TUN-Schicht 3 eine Verbindung herstellt. -- `user none` Ermöglicht das Verbinden von Benutzern mit einem nicht autorisierten Benutzer auf dem Server. -- `group $NOGROUP` Ermöglicht es, sich verbindende Benutzer mit einer nicht autorisierten Gruppe auf dem Server als Gruppe zu verknüpfen. -- `persist-key` Eine Autorisierungseinstellung für die Erstellung und den Neustart der virtuellen Schnittstelle -- `persist-tun` Ebenfalls eine Berechtigungseinstellung für die Erstellung und den Neustart der virtuellen Schnittstelle -- `keepalive 10 120` Eine Einstellung dafür, wie viele Verbindungen aktiv gehalten werden und wie lange die aktive Verbindung beendet wird, wenn keine Kommunikation hergestellt wird. -- `ifconfig-pool-persist ipp.txt` Eine Einstellung, um die von OpenVPN an Clients im virtuellen Netzwerk vergebenen IP-Adressen beizubehalten und ihnen dieselben Adressen zuzuweisen, wenn sie sich wieder verbinden -- `push "dhcp-option DNS 1.1.1.1"` Eine DNS-Einstellung, die der Server beim Verlassen des Netzwerks verwenden soll -- `compress` Der Teil, in dem Komprimierungsoptionen festgelegt werden -- `dh none` Eine Einstellung zum Ein- oder Ausschalten von Diffie-Hellman -- `ecdh-curve` Wenn Sie Elliptic Curve Diffie-Hellman verwenden, wird die Einstellung angepasst, neben der die Kurve ausgewählt werden muss -- `dh dh.pem`-Einstellung, die den Speicherort der PEM-Datei angibt, die Sie vorher erstellen müssen, wenn Sie Diffie-Hellman verwenden -- `tls-crypt tls-crypt.key` Erforderliche Einstellung, um die TLS-Schicht noch vor dem Pre-Shared Master zu verschlüsseln -- `tls-auth tls-auth.key 0`Einstellung, die es ermöglicht, Parteien über die Verschlüsselung hinaus in der Pre-Handshake-Phase der TLS-Schicht zu authentifizieren -- `crl-verify crl.pem` Einstellung um zu prüfen, ob die generierten Zertifikate über die CRL-Liste widerrufen werden oder nicht -- `ca ca.crt` Eine Einstellung, die den Speicherort des Zertifikats der Zertifizierungsstelle des generierten Zertifikats meldet -- `cert $SERVER_NAME.crt` Eine Einstellung, die den Speicherort des Zertifikats des Servers angibt -- `key $SERVER_NAME.key` Eine Einstellung, die den Speicherort des erforderlichen asymmetrischen geheimen Schlüssels neben dem Zertifikat des Servers angibt -- `auth $HMAC_ALG` Eine Einstellung, die beschreibt, welcher Hash-Algorithmus für den Datenkanal verwendet werden soll, und ggf. `tls-auth` -- `cipher $CIPHER` Eine Einstellung, die angibt, welcher Verschlüsselungsalgorithmus für den Datenkanal verwendet werden soll -- `ncp-ciphers $CIPHER` Eine Einstellung, die angibt, welche Verschlüsselungsalgorithmen der Server verwenden kann -- `tls-server` Eine Einstellung, die den Server anweist, den TLS-Kanal zu verwenden -- Eine Einstellung `tls-version-min 1.2` meldet die niedrigste Version, die auf dem TLS-Kanal verwendet werden soll -- `tls-cipher $CC_CIPHER` Die Verschlüsselung wird auch auf der TLS-Schicht verwendet, mit Ausnahme des Datenkanals, der die Einstellung ist, die die Verschlüsselung des Steuerkanals deklariert -- `client-config-dir /etc/openvpn/ccd` Einstellung, die angibt, wo Client-Einstellungsdateien aufbewahrt werden -- `status /var/log/openvpn/status.log` Einstellung, die angibt, wo Statusberichte geschrieben und wo Protokolldateien aufbewahrt werden -- `verb 3` Diese Einstellung, die die Abkürzung des Wortes Verbose ist, ist die Einstellung, wie detailliert der Statusbericht gegeben werden soll. - -### Die clientseitige Einstellungsdatei enthält die folgenden Einträge - -- `client` gibt an, dass sich das Gerät in der Client-Rolle befindet -- `proto tcp-client` meldet TCP als Protokoll -- `remote $IP $PORT` Der Teil, in dem die IP-Adresse und die Portnummer des/der zu verbindenden Server(s) festgelegt werden -- `dev tun` legt fest, welche der TUN/TAP-Schnittstellen verwendet werden sollen -- `resolve-retry infinite` Wir sagen Ihnen, wie lange Sie warten müssen, wenn sich die Adressauflösung aufgrund von IP oder DNS verzögert -- `nobind`-Einstellung, um keine Verbindung zu einer Adresse im lokalen Netzwerk herzustellen -- `persist-key` Ermöglicht das Lesen von Schlüsseldateien ohne zusätzliche Autorisierung beim Neustart -- `persist-tun` Es ermöglicht auch, dass die TUN/TAP-Schnittstelle beim Neustart ohne Autorisierung aufgeweckt wird -- `remote-cert-tls server` Überprüft das Zertifikat des verbundenen Servers auf TLS-Ebene -- `verify-x509-name $SERVER_NAME name` Befehl, der den Namen im Zertifikat angibt, zu dem der Server zurückkehren wird, und wie der Name des Servers lauten soll -- `auth $HMAC_ALG` Befehl, der angibt, welcher Algorithmus für die Validierung verwendet werden soll -- `auth-nocache` Speichert das für die Anmeldung erforderliche Passwort nicht -- `cipher $CIPHER` Befehl zur Auswahl des für die Verschlüsselung zu verwendenden Algorithmus -- `tls-client` aktiviert TLS während der TLS-Kommunikation und übernimmt die Client-Rolle -- `tls-version-min 1.2` Legt die niedrigste TLS-Version fest -- `tls-cipher $CC_CIPHER` wählt den Verschlüsselungsalgorithmus aus, der im TLS-Steuerkanal verwendet werden soll -- `ignore-unknown-option block-outside-dns` Verhindert, dass unbekannte DNS-Adressen verwendet werden -- `setenv opt block-outside-dns` blockiert DNS-Leaks für Windows 10 -- `Verb 3` Bestimmt den Grad der Berichterstattung -- `compress` Hier werden die Einstellungen des Komprimierungsalgorithmus gemeldet -- `"/etc/openvpn/easy-rsa/pki/ca.crt"` Hartcodierte Einbettung der erwarteten Server-Zertifizierungsstellendatei -- `"/etc/openvpn/easy-rsa/pki/issued/$CLIENT.crt"` Hartcodierte Einbettung der Client-Zertifikatsdatei -- `"/etc/openvpn/easy-rsa/pki/private/$CLIENT.key"` Hartcodierte Einbettung des asymmetrischen geheimen Schlüssels des Clients -- `"/etc/openvpn/tls-crypt.key"` Angabe der Schlüsseldatei für TLS-Crypt -- `"/etc/openvpn/tls-auth.key"` Angabe der Schlüsseldatei für die TLS-Authentifizierung -- `key-direction 1` weist Client und Server Rollen für die TLS-Layer-Verschlüsselung zu (0 und 1) - -Eine ausführliche Dokumentation dieser Einstellungen und mehr finden Sie auf der Webseite [OpenVPN](https://openvpn.net/community-resources/reference-manual-for-openvpn-2-4/). - -## Was passiert beim Aufbau einer OpenVPN-Verbindung? - -Jedes Mal, wenn ich mich mit OpenVPN verbinde, fühle ich mich, als würde R2-D2 ihre Pläne der Sternenflotte entführen. Die Leute wollen sich nicht immer einer genauen Prüfung unterziehen und bitten vielleicht jemanden, ihnen zu erklären, was und wie. In meiner Absicht, diesen Artikel zu schreiben, habe ich mir diese Frage tatsächlich gestellt und mich sehr bemüht, die Antwort zu bekommen. Ich möchte nicht, dass Sie sich so viel Mühe geben, aber ich kann nicht sagen, dass Sie es sofort hochladen sollen, denken Sie nicht an den Rest, es ist mein Job. Wie eingangs versprochen, werde ich Ihnen diesen Vorgang ausführlich erläutern und Ihnen die Entscheidung überlassen. So funktioniert der Prozess in einer OpenVPN-Verbindung, Vor- und Nachteile (wie ich es bisher herausfinden konnte). Sie bauen zunächst eine TCP/UDP-Verbindung auf. Sie führen einen Prozess wie jede Anwendung aus, die TCP verwendet, und wechseln dann zur TLS-Schicht. Sie führen einen Handshake und eine Authentifizierung auf der TLS-Schicht durch. Diese Schicht wird auch Steuerkanal genannt. Dann wird eine bestimmte Kommunikation festgelegt und der Datenkanal weitergegeben. Der Prozess der Ver- und Entschlüsselung der diesmal zu versendenden Datenpakete im Daten- bzw. Datenkanal beginnt. Dazu sprechen Geräte miteinander und Daten werden unter bestimmten gemeinsamen Bedingungen gesendet. Kurz gesagt, am Ende des von mir so beschriebenen Prozesses endet die von uns bei 0 begonnene Kommunikation mit dem sicheren und erwünschten Datenzugriff auf uns, oder es werden erneut Anfragen gesendet, diesmal auf umgekehrtem Weg, über die Verbindung that offen gehalten wird. So entsteht ein System wie ineinander verschachtelte Rohre. Wenn Sie hier das einzig Wichtige für den Artikel schreiben müssen: - -- Es wird `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P512` sein. - - Hier gibt die Eingabe `TLS` an, dass der Kontrollkanal über die TLS-Schicht ausgeführt wird. Andere Alternativen sind `SSL` oder `NULL`. - - Die Eingabe `ECDHE` gibt an, dass der erste Vorschlüssel unter Verwendung des elliptischen Diffie-Hellman-Algorithmus generiert wird. Andere Alternativen sind die Verwendung von `DHE`, `DH` oder nicht. - - Die `ECDSA`-Daten geben an, dass der Elliptic Digital Signature Certificate Algorithm für die gegenseitige Authentifizierung und den asymmetrischen Schlüssel verwendet wird. Eine weitere verfügbare Alternative ist `RSA`. Die anderen braucht man nicht zu zählen. - - Gibt den Verschlüsselungsalgorithmus an, der auf dem Datenkanal `AES_256_GCM` verwendet werden soll. Andere Alternativen sind `AES-128-CBC`, `AES-128-GCM` und `AES-256-CBC`. - - `SHA384` gibt den zu verwendenden Hash-Algorithmus an. Die andere Alternative ist `SHA256`. - - `P512` ermöglicht die Auswahl der elliptischen Kurve als Prime-512. Andere Alternativen sind `P-256` und `P-384`. - -### Der Prozess des Aufbaus der TCP-Verbindung - -Wenn Sie nun ein ungefähres Bild des Prozesses im Kopf haben, beginne ich mit der Erklärung des TCP-Prozesses. Nehmen wir an, wir haben in unserem Fall einen Client und einen Server, und die Verbindung besteht nur aus diesen beiden. Der Client sendet ein SYN (m)-Paket an den Server, mit dem er sich verbinden möchte. Als Antwort sendet der Server ein SYN (n)-Paket und ein ACK (m+1)-Paket über denselben Port. Der Client, der dies empfängt, gibt ebenfalls als Antwort ACK (n+1) zurück, und es findet ein 3-Wege-TCP-Handshake oder ein 3-Wege-TCP-Handshake statt. Somit haben wir einen offenen Kanal zwischen Client und Server über den angegebenen Port. - -![https://blog.shiftasia.com/what-happen-when-access-website (Datum: 08.04.2023)](/images/openvpn-full/TCP-Handshake.jpg) - ---- -![https://www.netscout.com/blog/asert/ddos-attacks-ssl-something-old-something-new (Datum: 08.04.2023)](/images/openvpn-full/TCP-Handshake-2.png) - -Wie auf den Fotos zu sehen, kann bei reibungslosem Ablauf die Kommunikation in 3 Schritten erfolgen. Aber wenn Sie fragen, warum wir das in 3 Schritten machen, geht das nicht auch kürzer? Ich würde (vorerst) nein sagen, nein, für eine Vollduplex-Kommunikation müssen beide Parteien SYN- und ACK-Pakete senden. Vielleicht erzähle ich Ihnen in Zukunft andere Wege, aber im Moment ist es so. Wie auch immer, der TCP/UDP-Teil ist immer kurz und einfach. - -### Prozess, der in der TLS-Schicht ausgeführt wird - -Nach dem Aufbau einer Kommunikation über TCP ist der Client die Person, die die Konversation auf eine andere Ebene bringt. Clients fordern immer etwas vom Server an oder fordern eine Antwort an. Im Allgemeinen reagieren Server nicht auf eine Anfrage, die nicht bei ihnen angekommen ist. Der Prozess läuft nach dem Prinzip `Erst Nachfrage, dann Angebot` ab. Ja, die Parteien befinden sich jetzt auf der TLS-Schicht. Der Client begrüßt zuerst den Server. Kein Scherz, es ist echt. Das erste vom Client gesendete Paket wird als `Client-Hello`-Paket bezeichnet. Neben diesem Paket (um den Vorgang zu beschleunigen) das Paket `Supported-Chipers`, das die unterstützten Verschlüsselungsalgorithmen angibt, eine vom Client zufällig generierte Nummer, ein `SNI`-Servernamensindikator, wenn mehr als ein Dienst vorhanden ist die auf derselben IP-Adresse ausgeführt werden, und ggf. die Sitzungs-ID. . Die Antwort des Servers darauf ist zunächst einmal ein höfliches Hallo. Denn das erste Paket, das der Server als Antwort sendet, heißt `Server-Hello`-Paket. Neben diesem Paket sendet das `Selected-Chiper`-Paket, das das Serverzertifikat, die unterstützten Verschlüsselungsalgorithmen und den ausgewählten Algorithmus angibt, eine von ihm generierte Zufallszahl, gegebenenfalls die Sitzungs-ID und eine SNI-ähnliche ID wenn sich mehr als ein Client über dieselbe IP verbindet. . Der Client verifiziert zunächst anhand des Serverzertifikats, ob es sich wirklich um die Person handelt, auf die er wartet, indem er die Kommunikation startet. Außerdem prüft der Server in manchen Fällen mit einem Zertifikat, ob der Client einer der Clients ist, die er erwartet. Wenn dieser gegenseitige Authentifizierungsprozess positiv ist, wird die nächste Stufe bestanden. Der Schlüsselerzeugungs- und Austauschprozess wird ausgelöst. In dieser Phase greift der Client erneut ein und sagt, dass er den Schlüssel mit dem Algorithmus ändern möchte, den er während dieser Kommunikation festgelegt hat, was als unsicher gilt. Die Parteien beginnen mit der Generierung eines Prekeys mit Diffie-Hellman oder ECDHE. Dazu werden Pre-Secrets von Client und Server geteilt. Die Antworten, die durch Ausführen einer Reihe mathematischer Operationen gefunden wurden, werden nach oben gesendet, und das gleiche Ergebnis wird durch erneutes Ausführen mathematischer Operationen erreicht. Das Ergebnis ist der erste Fore-Key, den sie sicher zwischen ihnen erstellt haben. Danach, mit dem von ihnen bestimmten Verschlüsselungsalgorithmus, Ein anderer Datenkanal als der Steuerkanal wird zur Kommunikation erstellt, und der Prozess wird von dort aus fortgesetzt. - -![https://www.researchgate.net/publication/298065605_A_multi-level_framework_to_identify_HTTPS_services (Datum: 08.04.2023)](/images/openvpn-full/TLS-Handshake.png) - ---- -![](/images/openvpn-full/TLS-Handshake-2.png) - -Wie auf den Fotos zu sehen ist, ist der Vorgang fast derselbe wie beim Herstellen einer Verbindung zu einer Webseite. Je nach Bedarf werden nur bestimmte Stufen hinzugefügt, entfernt oder geändert. Beispielsweise übermitteln die Parteien gemäß PFS, was für Advanced Privacy steht, den Front-Key nicht mit dem asymmetrischen Schlüssel des Servers. Da in diesem Fall für jede Sitzung derselbe Schlüssel verwendet wird, werden die Daten gespeichert und sind dann rückwirkend lesbar, indem auf einen Tag gewartet wird, an dem der Schlüssel enthüllt wird. Deshalb wurde diese Änderung vorgenommen. Auch hier möchte ich gemäß dem Zero-Trust-Bedrohungsmodell, dass jede Schicht und jeder Prozess den Prozess vorantreibt, ohne darauf zu vertrauen, dass die andere ihre Arbeit korrekt erledigt. Aus diesem Grund wollen wir, dass die Pakete gemäß der Funktion `tls-auth` verschlüsselt werden und die Integrität der ein- und ausgehenden Daten bereits im ersten Kommunikationsmoment in der TLS-Schicht überprüft wird. Vom ersten Moment an, in dem Sie Hallo sagen, können Dritte nicht verstehen, wovon Sie sprechen und in welcher Phase Sie sich befinden. Dazu wird die erste Kommunikation mit einem oder mehreren vorgegebenen Schlüsseln gestartet und bei Bedarf werden diese Schlüssel in regelmäßigen Abständen erneuert. So wird auch bis zur Erstellung des ersten Pre-Keys in der TLS-Schicht die Vertraulichkeit nicht kompromittiert und Unbefugte nicht umsonst erstellt. - -### Prozess, der in der Datenschicht ausgeführt wird - -Wenn dieser gesamte Vorgang erfolgreich abgeschlossen und der Datenkanal bestanden wurde, sind Sie nun beim besten Teil der Arbeit angelangt. Die Daten werden mit der AES-Verschlüsselungsmethode verschlüsselt. Während der Verschlüsselung werden die Tabellen gemäß dem CBC-GCM-Zählermodus gemäß Ihrer Auswahl gemischt, und bei diesem Vorgang wird gemäß Ihrer Auswahl ein 128- oder 256-Bit-Verschlüsselungsschlüssel verwendet. Unabhängig von Ihrer Wahl beträgt die Verschlüsselungsblocklänge natürlich 128 Bit. Nur die Länge des Verschlüsselungsschlüssels ändert sich. AES-256-GCM, das ich für diese Erklärung ausgewählt habe, ist ein AEAD-Verschlüsselungstyp. Es fasst die von ihm gesendeten Daten unabhängig von anderen Kanälen und Prozessen zu einem bestimmten Zeitpunkt zusammen und versendet sie zusammen mit der Zusammenfassung. Somit werden Authentifizierungs- und Verschlüsselungsfunktionen in AEAD erfüllt, was für `Authentication Encryption with Associated Data` steht. Es gibt ein Problem, das hier eine Unterscheidung erfordert. In welcher Phase und in welcher Reihenfolge werden wir die Verschlüsselungs- und Hash-Algorithmen verwenden? - -|||| -|:---:|:---:|:---:| -| ![Encrypt-then-MAC (EtM)](/images/openvpn-full/EtM.png) | ![Encrypt-and-MAC (E-and-M)](/images/openvpn-full/EaM.png) | ![MAC-then-Encrypt (MtE)](/images/openvpn-full/MtE.png) | - -> https://en.wikipedia.org/wiki/Authenticated_encryption (Datum: 08.04.2023) - -- Laut EtM, dem ersten Ansatz, werden die Daten zuerst verschlüsselt, dann als Ergebnis des Digests mit einem anderen Schlüssel verschlüsselt und das resultierende Ergebnis in Blöcken zusammen gesendet. Wenn wir uns reale Lösungen ansehen, die es verwenden, fällt uns zuerst das IPSec-Protokoll ein. Dies ist die einzige Methode, die die höchste Sicherheitsdefinition in AE erreichen kann, dies kann jedoch nur erreicht werden, wenn der verwendete MAC-Algorithmus frei von Korruption ist oder noch nicht geknackt wurde. Für SSHv2 sind auch verschiedene EtM-Cipher-Suites verfügbar. Beachten Sie jedoch, dass für Daten und Digest eine Schlüsseltrennung zwingend erforderlich ist (für Verschlüsselung und Schlüssel-Hashing müssen unterschiedliche Schlüssel verwendet werden), da Sie sonst je nach verwendeter Verschlüsselungsmethode und Hash-Funktion möglicherweise ein unsicheres Ergebnis erhalten. - -- Gemäß dem zweiten Ansatz, E&M, werden Klartextdaten verschlüsselt und daneben wird eine Zusammenfassung des Verschlüsselungszustands der Klartextdaten hinzugefügt. Obwohl hier nur ein Schlüssel verwendet wird, zeigt die Tatsache, dass zwei unterschiedliche Ergebnisse (Verschlüsselungsergebnis und Digest-Ergebnis) für dieselben Daten vorliegen, deutlich, dass die Sicherheit nicht gut genug ist. Als reale Lösung mit diesem System können wir die ersten Versionen von SSH als Beispiel anführen. Um dies zu verbessern, wurden Methoden wie das Verschlüsseln der gesendeten Zusammenfassungsdatei mit demselben Schlüssel ausprobiert. - -- Laut MtE, dem dritten und letzten mir bekannten Ansatz, wird eine Zusammenfassungsdatei auf Basis von Klartext generiert. Dann werden der Klartext und die Digest-Datei zusammen mit dem Schlüssel verschlüsselt. Der Chiffretext und die Chiffretextdatei werden zusammen gesendet. Wenn wir uns reale Lösungen ansehen, die es verwenden, sind das in erster Linie SSL/TLS-Implementierungen. Wir alle wissen, wie zuverlässig und nachhaltig SSL/TLS-Anwendungen an sich sind. Darüber hinaus wurden im Laufe der Jahre Verbesserungen wie `MAC-then-pad-then-encrypt` vorgenommen, um die Sicherheit zu erhöhen. Gemäß dieser Verbesserung wird zuerst der Klartext verdaut, dann auf die Blockgröße aufgefüllt und dann die Verschlüsselung durchgeführt. Dies führt zu einem noch zuverlässigeren Verschlüsselungsergebnis. Aber es gibt Fälle, in denen der Padding-Mechanismus Angriffe wie Padding Oracle verursacht, wenn er bestimmte Fehler macht. - -![https://community.openvpn.net/openvpn/wiki/Gigabit_Networks_Linux (Datum: 08.04.2023)](/images/openvpn-full/TAP-TUN.png) - -Nach der Auswahl des zu verwendenden AEAD-Ansatzes wird je nach Verwendung von TAP oder TUN der in der obigen Grafik dargestellte Weg beschritten. Gemäß diesem Pfad geht die im Benutzerbereich ausgeführte/gewünschte Aktion zu den TAP/TUN-Adaptern auf Kernel-Ebene. Da sich diese Adapter auf der Kernel-Ebene befinden, arbeiten sie sehr schnell. Dann führen die virtuellen Adapter die notwendige Verschlüsselung mit der entsprechenden Bibliothek durch, fügen ggf. den Digest hinzu und stellen die Paketgröße ein. Dann sendet der Server Pakete sequentiell über die Ethernet-Schnittstelle an die Ethernet-Schnittstelle des Clients. Der Client, der es erhält, konfiguriert die Pakete neu, organisiert sie, kombiniert sie bei Bedarf und entschlüsselt sie mit den erforderlichen Bibliotheken. Nach der Entschlüsselung überträgt es den Client über den virtuellen Adapter an den Endbenutzer. Als Ergebnis all dieser mathematischen Operationen und Bemühungen erreichte der Benutzer also nach einigen Zyklen den gewünschten Inhalt. Es ist ziemlich lang zu erklären, aber sehr einfach zu bedienen, liebe Leser. Sie müssen nur die entsprechende [Skriptseite](https://github.com/wiseweb-works/openvpn-most-secure-install/) auf meiner GitHub-Seite besuchen. Das zugehörige Skript nimmt all diese Anpassungen interaktiv für Sie vor. Alles, was Sie tun müssen, ist sich zurückzulehnen und zu genießen. - -# FAQ und Ende - -Erhielt mich per [Mail](mailto:wisewebworks@outlook.com), [Fosstodon](https://fosstodon.org/@wise) oder [GitHub](https://github.com/wiseweb-works) I werde versuchen, hier von Zeit zu Zeit Fragen hinzuzufügen. So kommen Sie historisch gesehen direkt zum Ergebnis, ohne darüber nachzudenken, welche Art von Fragen zu welchem ​​Zeitpunkt aufgetreten sind oder ob es eine Lösung gibt. Abgesehen davon, wenn es Fragen gibt, die einer zusätzlichen Erklärung bedürfen, ohne das technische Dokument zu ändern, denke ich, sie in diesen Abschnitt aufzunehmen. +--- +title: "Eingehender OpenVPN-Test" +date: 2022-03-27 +tags: ["linux", "ssl", "security", "ecc", "elliptic curve", "openvpn", "tls", "aes"] +author: "Wise" +draft: false +--- +# Einführung und Zusammenfassung + +Heute werden wir OpenVPN, meiner Meinung nach eine der wichtigsten Software der letzten Zeit, ausführlich überprüfen. In diesem Test werden wir zuerst darüber sprechen, wofür OpenVPN verwendet wird. Dann untersuchen wir, was wir zum Ausführen des Programms benötigen und was vor dem ersten Ausführen zu tun ist. Abschließend werde ich versuchen zu erklären, was vom ersten Moment des Verbindungsaufbaus bis zum letzten Schritt, wenn die Daten entschlüsselt werden, im Hintergrund vor sich geht. Daher schätze ich, dass unser Artikel aus 3 Teilen und gegebenenfalls einem Frage-Antwort-Abschnitt bestehen wird. Jetzt schnallen wir uns an und machen einen Ausflug in die tiefe und düstere Welt des Internets. + +## Was ist OpenVPN und wofür wird es verwendet? + +Heutzutage gibt es fast kein Geschäft, das nicht online erledigt werden kann. Sogar unsere Arbeit, die normalerweise nicht online ist, hat sich aufgrund der Pandemie und der neuen Normalität auf die Arbeit von zu Hause aus entwickelt. Es gab jedoch große Probleme, sowohl weil es eine Arbeitsmethode ist, an die wir nicht gewöhnt sind, als auch weil unsere Leute nicht sehr gut mit Technologie umgehen können. Bevor klar wurde, dass die Menschen sich von ihren Heimcomputern mit ihren Bürocomputern verbinden mussten, kamen einige Unternehmen auf frivole Ideen, wie zum Beispiel, Bürocomputer zu den Häusern der Mitarbeiter zu schicken. Sie haben sehr gut verstanden, wie falsch das war, aus dem Feedback, das sie in kurzer Zeit erhalten haben. Kurz gesagt, es wurde endlich akzeptiert, dass elektronische Geräte im Büro bleiben und irgendwie eine sichere und nachhaltige Verbindung aus der Ferne hergestellt werden sollte. Natürlich befanden sich Institutionen auch schon früher in solchen Nöten, aber eine solche Großsituation kam damals nicht in Frage. Vor der Pandemie wurden verschiedene Protokolle wie PPTP, L2TP, IPSec, IKev2, SSTP und schließlich OpenVPN verwendet. Dies sind normalerweise Abkürzungen für bestimmte lange und ausgefallene Wörter, und ihre grundlegende Logik besteht darin, zwei oder mehr Geräte zu verbinden und sie so zu verhalten, als ob sie sich im selben Netzwerk befinden. Ich werde nicht viel sagen, da Protokolle vor OpenVPN gewisse Schwächen, Langsamkeit und technische Schwierigkeiten bei der Implementierung mit sich brachten. OpenVPN ist der Name des Protokolls und Programms, das es mindestens 2 Geräten in der Rolle von Server und Client ermöglicht, sich miteinander zu verbinden, und zwar auf eine Weise, die Industriestandards entspricht. Ich verwende ein Remote-Desktop-Programm. Ich höre Sie anscheinend sagen, was die Notwendigkeit dafür ist. Leider müssen er und alle anderen Programme wie er grundsätzlich dieses Protokoll verwenden. Wenn Sie das Schildsymbol oder die Verbindungsdetails in TeamViewer, einem der bekanntesten, drücken, können Sie das OpenVPN-Protokoll sehen. + +## Was brauchen wir, um eine OpenVPN-Verbindung aufzubauen? + +Zunächst muss OpenVPN sowohl auf der Server- als auch auf der Clientseite (dem zu verbindenden Gerät) installiert werden. Dann sollte eine Einstellungsdatei (Konfigurationsdatei) bearbeitet werden, die die Bedingungen zeigt, unter denen die Geräte kommunizieren. Das Hauptereignis ist, dass diese Konfigurationsdatei vom Client generiert und verwendet wird. Diese Konfigurationsdatei ist unterteilt in server_config, die vom Server verwendet wird, und client_config, die vom Client verwendet wird. + +### Die vom Server verwaltete Einstellungsdatei enthält die folgenden Einträge + +- `Port 1194` gibt an, welcher Port eine Verbindungsanfrage zum Herstellen der OpenVPN-Verbindung erhält. +- `proto tcp` Verbindung über TCP oder UDP möglich. Einstellungseintrag zur Auswahl eingetragen. +- `dev tun` TAP- oder TUN-Schnittstelle kann verwendet werden. Dies sind virtuelle Schnittstellen. TAP-Schicht 2 stellt eine Verbindung her, während TUN-Schicht 3 eine Verbindung herstellt. +- `user none` Ermöglicht das Verbinden von Benutzern mit einem nicht autorisierten Benutzer auf dem Server. +- `group $NOGROUP` Ermöglicht es, sich verbindende Benutzer mit einer nicht autorisierten Gruppe auf dem Server als Gruppe zu verknüpfen. +- `persist-key` Eine Autorisierungseinstellung für die Erstellung und den Neustart der virtuellen Schnittstelle +- `persist-tun` Ebenfalls eine Berechtigungseinstellung für die Erstellung und den Neustart der virtuellen Schnittstelle +- `keepalive 10 120` Eine Einstellung dafür, wie viele Verbindungen aktiv gehalten werden und wie lange die aktive Verbindung beendet wird, wenn keine Kommunikation hergestellt wird. +- `ifconfig-pool-persist ipp.txt` Eine Einstellung, um die von OpenVPN an Clients im virtuellen Netzwerk vergebenen IP-Adressen beizubehalten und ihnen dieselben Adressen zuzuweisen, wenn sie sich wieder verbinden +- `push "dhcp-option DNS 1.1.1.1"` Eine DNS-Einstellung, die der Server beim Verlassen des Netzwerks verwenden soll +- `compress` Der Teil, in dem Komprimierungsoptionen festgelegt werden +- `dh none` Eine Einstellung zum Ein- oder Ausschalten von Diffie-Hellman +- `ecdh-curve` Wenn Sie Elliptic Curve Diffie-Hellman verwenden, wird die Einstellung angepasst, neben der die Kurve ausgewählt werden muss +- `dh dh.pem`-Einstellung, die den Speicherort der PEM-Datei angibt, die Sie vorher erstellen müssen, wenn Sie Diffie-Hellman verwenden +- `tls-crypt tls-crypt.key` Erforderliche Einstellung, um die TLS-Schicht noch vor dem Pre-Shared Master zu verschlüsseln +- `tls-auth tls-auth.key 0`Einstellung, die es ermöglicht, Parteien über die Verschlüsselung hinaus in der Pre-Handshake-Phase der TLS-Schicht zu authentifizieren +- `crl-verify crl.pem` Einstellung um zu prüfen, ob die generierten Zertifikate über die CRL-Liste widerrufen werden oder nicht +- `ca ca.crt` Eine Einstellung, die den Speicherort des Zertifikats der Zertifizierungsstelle des generierten Zertifikats meldet +- `cert $SERVER_NAME.crt` Eine Einstellung, die den Speicherort des Zertifikats des Servers angibt +- `key $SERVER_NAME.key` Eine Einstellung, die den Speicherort des erforderlichen asymmetrischen geheimen Schlüssels neben dem Zertifikat des Servers angibt +- `auth $HMAC_ALG` Eine Einstellung, die beschreibt, welcher Hash-Algorithmus für den Datenkanal verwendet werden soll, und ggf. `tls-auth` +- `cipher $CIPHER` Eine Einstellung, die angibt, welcher Verschlüsselungsalgorithmus für den Datenkanal verwendet werden soll +- `ncp-ciphers $CIPHER` Eine Einstellung, die angibt, welche Verschlüsselungsalgorithmen der Server verwenden kann +- `tls-server` Eine Einstellung, die den Server anweist, den TLS-Kanal zu verwenden +- Eine Einstellung `tls-version-min 1.2` meldet die niedrigste Version, die auf dem TLS-Kanal verwendet werden soll +- `tls-cipher $CC_CIPHER` Die Verschlüsselung wird auch auf der TLS-Schicht verwendet, mit Ausnahme des Datenkanals, der die Einstellung ist, die die Verschlüsselung des Steuerkanals deklariert +- `client-config-dir /etc/openvpn/ccd` Einstellung, die angibt, wo Client-Einstellungsdateien aufbewahrt werden +- `status /var/log/openvpn/status.log` Einstellung, die angibt, wo Statusberichte geschrieben und wo Protokolldateien aufbewahrt werden +- `verb 3` Diese Einstellung, die die Abkürzung des Wortes Verbose ist, ist die Einstellung, wie detailliert der Statusbericht gegeben werden soll. + +### Die clientseitige Einstellungsdatei enthält die folgenden Einträge + +- `client` gibt an, dass sich das Gerät in der Client-Rolle befindet +- `proto tcp-client` meldet TCP als Protokoll +- `remote $IP $PORT` Der Teil, in dem die IP-Adresse und die Portnummer des/der zu verbindenden Server(s) festgelegt werden +- `dev tun` legt fest, welche der TUN/TAP-Schnittstellen verwendet werden sollen +- `resolve-retry infinite` Wir sagen Ihnen, wie lange Sie warten müssen, wenn sich die Adressauflösung aufgrund von IP oder DNS verzögert +- `nobind`-Einstellung, um keine Verbindung zu einer Adresse im lokalen Netzwerk herzustellen +- `persist-key` Ermöglicht das Lesen von Schlüsseldateien ohne zusätzliche Autorisierung beim Neustart +- `persist-tun` Es ermöglicht auch, dass die TUN/TAP-Schnittstelle beim Neustart ohne Autorisierung aufgeweckt wird +- `remote-cert-tls server` Überprüft das Zertifikat des verbundenen Servers auf TLS-Ebene +- `verify-x509-name $SERVER_NAME name` Befehl, der den Namen im Zertifikat angibt, zu dem der Server zurückkehren wird, und wie der Name des Servers lauten soll +- `auth $HMAC_ALG` Befehl, der angibt, welcher Algorithmus für die Validierung verwendet werden soll +- `auth-nocache` Speichert das für die Anmeldung erforderliche Passwort nicht +- `cipher $CIPHER` Befehl zur Auswahl des für die Verschlüsselung zu verwendenden Algorithmus +- `tls-client` aktiviert TLS während der TLS-Kommunikation und übernimmt die Client-Rolle +- `tls-version-min 1.2` Legt die niedrigste TLS-Version fest +- `tls-cipher $CC_CIPHER` wählt den Verschlüsselungsalgorithmus aus, der im TLS-Steuerkanal verwendet werden soll +- `ignore-unknown-option block-outside-dns` Verhindert, dass unbekannte DNS-Adressen verwendet werden +- `setenv opt block-outside-dns` blockiert DNS-Leaks für Windows 10 +- `Verb 3` Bestimmt den Grad der Berichterstattung +- `compress` Hier werden die Einstellungen des Komprimierungsalgorithmus gemeldet +- `"/etc/openvpn/easy-rsa/pki/ca.crt"` Hartcodierte Einbettung der erwarteten Server-Zertifizierungsstellendatei +- `"/etc/openvpn/easy-rsa/pki/issued/$CLIENT.crt"` Hartcodierte Einbettung der Client-Zertifikatsdatei +- `"/etc/openvpn/easy-rsa/pki/private/$CLIENT.key"` Hartcodierte Einbettung des asymmetrischen geheimen Schlüssels des Clients +- `"/etc/openvpn/tls-crypt.key"` Angabe der Schlüsseldatei für TLS-Crypt +- `"/etc/openvpn/tls-auth.key"` Angabe der Schlüsseldatei für die TLS-Authentifizierung +- `key-direction 1` weist Client und Server Rollen für die TLS-Layer-Verschlüsselung zu (0 und 1) + +Eine ausführliche Dokumentation dieser Einstellungen und mehr finden Sie auf der Webseite [OpenVPN](https://openvpn.net/community-resources/reference-manual-for-openvpn-2-4/). + +## Was passiert beim Aufbau einer OpenVPN-Verbindung? + +Jedes Mal, wenn ich mich mit OpenVPN verbinde, fühle ich mich, als würde R2-D2 ihre Pläne der Sternenflotte entführen. Die Leute wollen sich nicht immer einer genauen Prüfung unterziehen und bitten vielleicht jemanden, ihnen zu erklären, was und wie. In meiner Absicht, diesen Artikel zu schreiben, habe ich mir diese Frage tatsächlich gestellt und mich sehr bemüht, die Antwort zu bekommen. Ich möchte nicht, dass Sie sich so viel Mühe geben, aber ich kann nicht sagen, dass Sie es sofort hochladen sollen, denken Sie nicht an den Rest, es ist mein Job. Wie eingangs versprochen, werde ich Ihnen diesen Vorgang ausführlich erläutern und Ihnen die Entscheidung überlassen. So funktioniert der Prozess in einer OpenVPN-Verbindung, Vor- und Nachteile (wie ich es bisher herausfinden konnte). Sie bauen zunächst eine TCP/UDP-Verbindung auf. Sie führen einen Prozess wie jede Anwendung aus, die TCP verwendet, und wechseln dann zur TLS-Schicht. Sie führen einen Handshake und eine Authentifizierung auf der TLS-Schicht durch. Diese Schicht wird auch Steuerkanal genannt. Dann wird eine bestimmte Kommunikation festgelegt und der Datenkanal weitergegeben. Der Prozess der Ver- und Entschlüsselung der diesmal zu versendenden Datenpakete im Daten- bzw. Datenkanal beginnt. Dazu sprechen Geräte miteinander und Daten werden unter bestimmten gemeinsamen Bedingungen gesendet. Kurz gesagt, am Ende des von mir so beschriebenen Prozesses endet die von uns bei 0 begonnene Kommunikation mit dem sicheren und erwünschten Datenzugriff auf uns, oder es werden erneut Anfragen gesendet, diesmal auf umgekehrtem Weg, über die Verbindung that offen gehalten wird. So entsteht ein System wie ineinander verschachtelte Rohre. Wenn Sie hier das einzig Wichtige für den Artikel schreiben müssen: + +- Es wird `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P512` sein. + - Hier gibt die Eingabe `TLS` an, dass der Kontrollkanal über die TLS-Schicht ausgeführt wird. Andere Alternativen sind `SSL` oder `NULL`. + - Die Eingabe `ECDHE` gibt an, dass der erste Vorschlüssel unter Verwendung des elliptischen Diffie-Hellman-Algorithmus generiert wird. Andere Alternativen sind die Verwendung von `DHE`, `DH` oder nicht. + - Die `ECDSA`-Daten geben an, dass der Elliptic Digital Signature Certificate Algorithm für die gegenseitige Authentifizierung und den asymmetrischen Schlüssel verwendet wird. Eine weitere verfügbare Alternative ist `RSA`. Die anderen braucht man nicht zu zählen. + - Gibt den Verschlüsselungsalgorithmus an, der auf dem Datenkanal `AES_256_GCM` verwendet werden soll. Andere Alternativen sind `AES-128-CBC`, `AES-128-GCM` und `AES-256-CBC`. + - `SHA384` gibt den zu verwendenden Hash-Algorithmus an. Die andere Alternative ist `SHA256`. + - `P512` ermöglicht die Auswahl der elliptischen Kurve als Prime-512. Andere Alternativen sind `P-256` und `P-384`. + +### Der Prozess des Aufbaus der TCP-Verbindung + +Wenn Sie nun ein ungefähres Bild des Prozesses im Kopf haben, beginne ich mit der Erklärung des TCP-Prozesses. Nehmen wir an, wir haben in unserem Fall einen Client und einen Server, und die Verbindung besteht nur aus diesen beiden. Der Client sendet ein SYN (m)-Paket an den Server, mit dem er sich verbinden möchte. Als Antwort sendet der Server ein SYN (n)-Paket und ein ACK (m+1)-Paket über denselben Port. Der Client, der dies empfängt, gibt ebenfalls als Antwort ACK (n+1) zurück, und es findet ein 3-Wege-TCP-Handshake oder ein 3-Wege-TCP-Handshake statt. Somit haben wir einen offenen Kanal zwischen Client und Server über den angegebenen Port. + +![https://blog.shiftasia.com/what-happen-when-access-website (Datum: 08.04.2023)](/images/openvpn-full/TCP-Handshake.jpg) + +--- +![https://www.netscout.com/blog/asert/ddos-attacks-ssl-something-old-something-new (Datum: 08.04.2023)](/images/openvpn-full/TCP-Handshake-2.png) + +Wie auf den Fotos zu sehen, kann bei reibungslosem Ablauf die Kommunikation in 3 Schritten erfolgen. Aber wenn Sie fragen, warum wir das in 3 Schritten machen, geht das nicht auch kürzer? Ich würde (vorerst) nein sagen, nein, für eine Vollduplex-Kommunikation müssen beide Parteien SYN- und ACK-Pakete senden. Vielleicht erzähle ich Ihnen in Zukunft andere Wege, aber im Moment ist es so. Wie auch immer, der TCP/UDP-Teil ist immer kurz und einfach. + +### Prozess, der in der TLS-Schicht ausgeführt wird + +Nach dem Aufbau einer Kommunikation über TCP ist der Client die Person, die die Konversation auf eine andere Ebene bringt. Clients fordern immer etwas vom Server an oder fordern eine Antwort an. Im Allgemeinen reagieren Server nicht auf eine Anfrage, die nicht bei ihnen angekommen ist. Der Prozess läuft nach dem Prinzip `Erst Nachfrage, dann Angebot` ab. Ja, die Parteien befinden sich jetzt auf der TLS-Schicht. Der Client begrüßt zuerst den Server. Kein Scherz, es ist echt. Das erste vom Client gesendete Paket wird als `Client-Hello`-Paket bezeichnet. Neben diesem Paket (um den Vorgang zu beschleunigen) das Paket `Supported-Chipers`, das die unterstützten Verschlüsselungsalgorithmen angibt, eine vom Client zufällig generierte Nummer, ein `SNI`-Servernamensindikator, wenn mehr als ein Dienst vorhanden ist die auf derselben IP-Adresse ausgeführt werden, und ggf. die Sitzungs-ID. . Die Antwort des Servers darauf ist zunächst einmal ein höfliches Hallo. Denn das erste Paket, das der Server als Antwort sendet, heißt `Server-Hello`-Paket. Neben diesem Paket sendet das `Selected-Chiper`-Paket, das das Serverzertifikat, die unterstützten Verschlüsselungsalgorithmen und den ausgewählten Algorithmus angibt, eine von ihm generierte Zufallszahl, gegebenenfalls die Sitzungs-ID und eine SNI-ähnliche ID wenn sich mehr als ein Client über dieselbe IP verbindet. . Der Client verifiziert zunächst anhand des Serverzertifikats, ob es sich wirklich um die Person handelt, auf die er wartet, indem er die Kommunikation startet. Außerdem prüft der Server in manchen Fällen mit einem Zertifikat, ob der Client einer der Clients ist, die er erwartet. Wenn dieser gegenseitige Authentifizierungsprozess positiv ist, wird die nächste Stufe bestanden. Der Schlüsselerzeugungs- und Austauschprozess wird ausgelöst. In dieser Phase greift der Client erneut ein und sagt, dass er den Schlüssel mit dem Algorithmus ändern möchte, den er während dieser Kommunikation festgelegt hat, was als unsicher gilt. Die Parteien beginnen mit der Generierung eines Prekeys mit Diffie-Hellman oder ECDHE. Dazu werden Pre-Secrets von Client und Server geteilt. Die Antworten, die durch Ausführen einer Reihe mathematischer Operationen gefunden wurden, werden nach oben gesendet, und das gleiche Ergebnis wird durch erneutes Ausführen mathematischer Operationen erreicht. Das Ergebnis ist der erste Fore-Key, den sie sicher zwischen ihnen erstellt haben. Danach, mit dem von ihnen bestimmten Verschlüsselungsalgorithmus, Ein anderer Datenkanal als der Steuerkanal wird zur Kommunikation erstellt, und der Prozess wird von dort aus fortgesetzt. + +![https://www.researchgate.net/publication/298065605_A_multi-level_framework_to_identify_HTTPS_services (Datum: 08.04.2023)](/images/openvpn-full/TLS-Handshake.png) + +--- +![](/images/openvpn-full/TLS-Handshake-2.png) + +Wie auf den Fotos zu sehen ist, ist der Vorgang fast derselbe wie beim Herstellen einer Verbindung zu einer Webseite. Je nach Bedarf werden nur bestimmte Stufen hinzugefügt, entfernt oder geändert. Beispielsweise übermitteln die Parteien gemäß PFS, was für Advanced Privacy steht, den Front-Key nicht mit dem asymmetrischen Schlüssel des Servers. Da in diesem Fall für jede Sitzung derselbe Schlüssel verwendet wird, werden die Daten gespeichert und sind dann rückwirkend lesbar, indem auf einen Tag gewartet wird, an dem der Schlüssel enthüllt wird. Deshalb wurde diese Änderung vorgenommen. Auch hier möchte ich gemäß dem Zero-Trust-Bedrohungsmodell, dass jede Schicht und jeder Prozess den Prozess vorantreibt, ohne darauf zu vertrauen, dass die andere ihre Arbeit korrekt erledigt. Aus diesem Grund wollen wir, dass die Pakete gemäß der Funktion `tls-auth` verschlüsselt werden und die Integrität der ein- und ausgehenden Daten bereits im ersten Kommunikationsmoment in der TLS-Schicht überprüft wird. Vom ersten Moment an, in dem Sie Hallo sagen, können Dritte nicht verstehen, wovon Sie sprechen und in welcher Phase Sie sich befinden. Dazu wird die erste Kommunikation mit einem oder mehreren vorgegebenen Schlüsseln gestartet und bei Bedarf werden diese Schlüssel in regelmäßigen Abständen erneuert. So wird auch bis zur Erstellung des ersten Pre-Keys in der TLS-Schicht die Vertraulichkeit nicht kompromittiert und Unbefugte nicht umsonst erstellt. + +### Prozess, der in der Datenschicht ausgeführt wird + +Wenn dieser gesamte Vorgang erfolgreich abgeschlossen und der Datenkanal bestanden wurde, sind Sie nun beim besten Teil der Arbeit angelangt. Die Daten werden mit der AES-Verschlüsselungsmethode verschlüsselt. Während der Verschlüsselung werden die Tabellen gemäß dem CBC-GCM-Zählermodus gemäß Ihrer Auswahl gemischt, und bei diesem Vorgang wird gemäß Ihrer Auswahl ein 128- oder 256-Bit-Verschlüsselungsschlüssel verwendet. Unabhängig von Ihrer Wahl beträgt die Verschlüsselungsblocklänge natürlich 128 Bit. Nur die Länge des Verschlüsselungsschlüssels ändert sich. AES-256-GCM, das ich für diese Erklärung ausgewählt habe, ist ein AEAD-Verschlüsselungstyp. Es fasst die von ihm gesendeten Daten unabhängig von anderen Kanälen und Prozessen zu einem bestimmten Zeitpunkt zusammen und versendet sie zusammen mit der Zusammenfassung. Somit werden Authentifizierungs- und Verschlüsselungsfunktionen in AEAD erfüllt, was für `Authentication Encryption with Associated Data` steht. Es gibt ein Problem, das hier eine Unterscheidung erfordert. In welcher Phase und in welcher Reihenfolge werden wir die Verschlüsselungs- und Hash-Algorithmen verwenden? + +|||| +|:---:|:---:|:---:| +| ![Encrypt-then-MAC (EtM)](/images/openvpn-full/EtM.png) | ![Encrypt-and-MAC (E-and-M)](/images/openvpn-full/EaM.png) | ![MAC-then-Encrypt (MtE)](/images/openvpn-full/MtE.png) | + +> https://en.wikipedia.org/wiki/Authenticated_encryption (Datum: 08.04.2023) + +- Laut EtM, dem ersten Ansatz, werden die Daten zuerst verschlüsselt, dann als Ergebnis des Digests mit einem anderen Schlüssel verschlüsselt und das resultierende Ergebnis in Blöcken zusammen gesendet. Wenn wir uns reale Lösungen ansehen, die es verwenden, fällt uns zuerst das IPSec-Protokoll ein. Dies ist die einzige Methode, die die höchste Sicherheitsdefinition in AE erreichen kann, dies kann jedoch nur erreicht werden, wenn der verwendete MAC-Algorithmus frei von Korruption ist oder noch nicht geknackt wurde. Für SSHv2 sind auch verschiedene EtM-Cipher-Suites verfügbar. Beachten Sie jedoch, dass für Daten und Digest eine Schlüsseltrennung zwingend erforderlich ist (für Verschlüsselung und Schlüssel-Hashing müssen unterschiedliche Schlüssel verwendet werden), da Sie sonst je nach verwendeter Verschlüsselungsmethode und Hash-Funktion möglicherweise ein unsicheres Ergebnis erhalten. + +- Gemäß dem zweiten Ansatz, E&M, werden Klartextdaten verschlüsselt und daneben wird eine Zusammenfassung des Verschlüsselungszustands der Klartextdaten hinzugefügt. Obwohl hier nur ein Schlüssel verwendet wird, zeigt die Tatsache, dass zwei unterschiedliche Ergebnisse (Verschlüsselungsergebnis und Digest-Ergebnis) für dieselben Daten vorliegen, deutlich, dass die Sicherheit nicht gut genug ist. Als reale Lösung mit diesem System können wir die ersten Versionen von SSH als Beispiel anführen. Um dies zu verbessern, wurden Methoden wie das Verschlüsseln der gesendeten Zusammenfassungsdatei mit demselben Schlüssel ausprobiert. + +- Laut MtE, dem dritten und letzten mir bekannten Ansatz, wird eine Zusammenfassungsdatei auf Basis von Klartext generiert. Dann werden der Klartext und die Digest-Datei zusammen mit dem Schlüssel verschlüsselt. Der Chiffretext und die Chiffretextdatei werden zusammen gesendet. Wenn wir uns reale Lösungen ansehen, die es verwenden, sind das in erster Linie SSL/TLS-Implementierungen. Wir alle wissen, wie zuverlässig und nachhaltig SSL/TLS-Anwendungen an sich sind. Darüber hinaus wurden im Laufe der Jahre Verbesserungen wie `MAC-then-pad-then-encrypt` vorgenommen, um die Sicherheit zu erhöhen. Gemäß dieser Verbesserung wird zuerst der Klartext verdaut, dann auf die Blockgröße aufgefüllt und dann die Verschlüsselung durchgeführt. Dies führt zu einem noch zuverlässigeren Verschlüsselungsergebnis. Aber es gibt Fälle, in denen der Padding-Mechanismus Angriffe wie Padding Oracle verursacht, wenn er bestimmte Fehler macht. + +![https://community.openvpn.net/openvpn/wiki/Gigabit_Networks_Linux (Datum: 08.04.2023)](/images/openvpn-full/TAP-TUN.png) + +Nach der Auswahl des zu verwendenden AEAD-Ansatzes wird je nach Verwendung von TAP oder TUN der in der obigen Grafik dargestellte Weg beschritten. Gemäß diesem Pfad geht die im Benutzerbereich ausgeführte/gewünschte Aktion zu den TAP/TUN-Adaptern auf Kernel-Ebene. Da sich diese Adapter auf der Kernel-Ebene befinden, arbeiten sie sehr schnell. Dann führen die virtuellen Adapter die notwendige Verschlüsselung mit der entsprechenden Bibliothek durch, fügen ggf. den Digest hinzu und stellen die Paketgröße ein. Dann sendet der Server Pakete sequentiell über die Ethernet-Schnittstelle an die Ethernet-Schnittstelle des Clients. Der Client, der es erhält, konfiguriert die Pakete neu, organisiert sie, kombiniert sie bei Bedarf und entschlüsselt sie mit den erforderlichen Bibliotheken. Nach der Entschlüsselung überträgt es den Client über den virtuellen Adapter an den Endbenutzer. Als Ergebnis all dieser mathematischen Operationen und Bemühungen erreichte der Benutzer also nach einigen Zyklen den gewünschten Inhalt. Es ist ziemlich lang zu erklären, aber sehr einfach zu bedienen, liebe Leser. Sie müssen nur die entsprechende [Skriptseite](https://github.com/wiseweb-works/openvpn-most-secure-install/) auf meiner GitHub-Seite besuchen. Das zugehörige Skript nimmt all diese Anpassungen interaktiv für Sie vor. Alles, was Sie tun müssen, ist sich zurückzulehnen und zu genießen. + +# FAQ und Ende + +Erhielt mich per [Mail](mailto:wisewebworks@outlook.com), [Fosstodon](https://fosstodon.org/@wise) oder [GitHub](https://github.com/wiseweb-works) I werde versuchen, hier von Zeit zu Zeit Fragen hinzuzufügen. So kommen Sie historisch gesehen direkt zum Ergebnis, ohne darüber nachzudenken, welche Art von Fragen zu welchem ​​Zeitpunkt aufgetreten sind oder ob es eine Lösung gibt. Abgesehen davon, wenn es Fragen gibt, die einer zusätzlichen Erklärung bedürfen, ohne das technische Dokument zu ändern, denke ich, sie in diesen Abschnitt aufzunehmen. diff --git a/content/post/openvpn-full-anlatim.en.md b/content/post/openvpn-full-anlatim.en.md index 6d908330..4463ac6a 100644 --- a/content/post/openvpn-full-anlatim.en.md +++ b/content/post/openvpn-full-anlatim.en.md @@ -1,140 +1,140 @@ ---- -title: "OpenVPN In-Depth Review" -date: 2022-03-27 -tags: ["linux", "ssl", "security", "ecc", "elliptic curve", "openvpn", "tls", "aes"] -author: "Wise" -draft: false ---- -# Introduction and Summary - -Today, we will make an in-depth review of OpenVPN, one of the most important software of recent times, in my opinion. In this review, we will first talk about what OpenVPN is used for. Then we will examine what we need to run the program and what needs to be done before the first run. Finally, I will try to explain what goes on in the background from the first moment the connection is started to the last step when the data is decrypted. Therefore, I guess our article will consist of 3 parts and a question-answer section if necessary. Now let's buckle up and take a trip to the deep and gloomy world of the internet. - -## What is OpenVPN and what is it used for? - -Today, there is almost no business that cannot be done online. Even our work, which is not normally online, has evolved to work from home due to the pandemic and the new normal. However, there were big problems both because it is a working method that we are not used to and because our people are not very good with technology. Before it became clear that people needed to connect from their home computers to their office computers, some companies came up with frivolous ideas such as sending office computers to employees' homes. They understood very well how wrong this was from the feedback they received in a short time. In short, it was finally accepted that electronic devices should remain in the office and somehow a secure and sustainable connection should be made remotely. Of course, institutions found themselves in such needs before, but such a large-scale situation was not in question back then. Before the pandemic, it used various protocols such as PPTP, L2TP, IPSec, IKev2, SSTP and finally OpenVPN. These are usually abbreviations for certain long and fancy words and their basic logic is to connect two or more devices and make them act as if they are on the same network. I won't talk much, as protocols prior to OpenVPN brought with them certain weaknesses, slowness, and technical difficulties with its implementation. OpenVPN is the name of the protocol and program that allows at least 2 devices in the role of server and client to connect to each other and do this in a way that meets industry standards. I'm using a remote desktop program, I seem to hear you say what is the need for this. Unfortunately, he and all other programs like him basically have to use this protocol. If you press the shield icon or the connection details in TeamViewer, one of the most famous, you can see the OpenVPN protocol. - -## What do we need to establish an OpenVPN connection? - -First of all, OpenVPN must be installed on both the server and client (the device to be connected) side. Then, a settings (config) file should be edited that shows the conditions under which the devices will communicate. The main event is that this config file is generated and used by the client. This config file is divided into server_config used by the server and client_config used by the client. - -### The settings file maintained by the server contains the following entries - -- `port 1194` specifies which port it will receive a connection request to make the OpenVPN connection. -- `proto tcp` Connection possible over TCP or UDP. Setting entry entered for selection. -- `dev tun` TAP or TUN interface can be used. These are virtual interfaces. TAP layer 2 establishes a connection, while TUN layer 3 establishes a connection. -- `user nobody` Enables connecting users to an unauthorized user on the server. -- `group $NOGROUP` It allows connecting users to be linked to an unauthorized group on the server as a group. -- `persist-key` An authorization setting for the creation and restart of the virtual interface -- `persist-tun` Also an authorization setting for the creation and restart of the virtual interface -- `keepalive 10 120` A setting for how many connections will be kept active and how long the active connection will be terminated if no communication is established. -- `ifconfig-pool-persist ipp.txt` A setting to keep the IP addresses given by OpenVPN to clients in the virtual network and give them the same addresses if they reconnect -- `push "dhcp-option DNS 1.1.1.1"` A DNS setting for the server to use when exiting the network -- `compress` The part where compression options are set -- `dh none` A setting for turning Diffie-Hellman on or off -- `ecdh-curve` If you are using Elliptic Curve Diffie-Hellman, the setting next to which the curve you need to select is adjusted -- `dh dh.pem` setting specifying the location of the PEM file you need to create beforehand if you are using Diffie-Hellman -- `tls-crypt tls-crypt.key` Required setting to encrypt TLS layer even before pre-shared master -- `tls-auth tls-auth.key 0` setting that allows parties to be authenticated beyond encryption at the pre-handshake stage of the TLS layer -- `crl-verify crl.pem` Setting to check whether the generated certificates are revoked or not via the CRL list -- `ca ca.crt` A setting that reports the location of the certificate of the certificate authority of the generated certificate -- `cert $SERVER_NAME.crt` A setting that tells the location of the server's certificate -- `key $SERVER_NAME.key` A setting indicating the location of the required asymmetric secret key next to the server's certificate -- `auth $HMAC_ALG` A setting describing which hash algorithm to use for the data channel and, if necessary, `tls-auth` -- `cipher $CIPHER` A setting that tells which encryption algorithm to use for the data channel -- `ncp-ciphers $CIPHER` A setting declaring which encryption algorithms the server can use -- `tls-server` A setting that tells the server to use the TLS channel -- A setting `tls-version-min 1.2` reports the lowest version to be used on the TLS channel -- `tls-cipher $CC_CIPHER` Encryption is also used at TLS layer, except for data channel, which is the setting declaring control channel encryption -- `client-config-dir /etc/openvpn/ccd` Setting that tells where client settings files are kept -- `status /var/log/openvpn/status.log` Setting that tells where status reports are written and where log files are kept -- `verb 3` This setting, which is the abbreviation of the word Verbose, is the setting of how detailed the status report is to be given. - -### The client-side settings file contains the following entries - -- `client` indicates that the device is in the client role -- `proto tcp-client` reports to use TCP as protocol -- `remote $IP $PORT` The part where the IP address and Port number of the server(s) to be connected are set -- `dev tun` sets which of the TUN/TAP interfaces to use -- `resolve-retry infinite` We tell you how long to wait if address resolution is delayed due to IP or DNS -- `nobind` setting to not connect to any address in the local -- `persist-key` Allows key files to be read without additional authorization on reboot -- `persist-tun` It also allows the TUN/TAP interface to be woken up without authorization on reboot -- `remote-cert-tls server` Verifies the certificate of the connected server at TLS layer -- `verify-x509-name $SERVER_NAME name` Command that tells the name in the certificate that the server will return to and what the name of the server should be -- `auth $HMAC_ALG` Command that tells which algorithm to use for validation -- `auth-nocache` Does not cache the password required for login -- `cipher $CIPHER` Command to select the algorithm to be used for encryption -- `tls-client` enables TLS during TLS communication and assumes the client role -- `tls-version-min 1.2` Sets the lowest TLS version -- `tls-cipher $CC_CIPHER` selects the encryption algorithm to use in the TLS control channel -- `ignore-unknown-option block-outside-dns` Prevents unknown DNS addresses from being used -- `setenv opt block-outside-dns` blocks DNS leaks for Windows 10 -- `verb 3` Determines the degree of reporting -- `compress` Compression algorithm settings are reported here -- `"/etc/openvpn/easy-rsa/pki/ca.crt"` Hard-Coded embedding of expected server certificate authority file -- `"/etc/openvpn/easy-rsa/pki/issued/$CLIENT.crt"` Hard-Coded embedding of client certificate file -- `"/etc/openvpn/easy-rsa/pki/private/$CLIENT.key"` Hard-Coded embedding of client asymmetric secret key -- `"/etc/openvpn/tls-crypt.key"` Specifying the key file for TLS crypt -- `"/etc/openvpn/tls-auth.key"` Specifying the key file for TLS auth -- `key-direction 1` assigns roles to client and server for TLS layer encryption (0 and 1) - -You can find detailed documentation of these settings and more on the [OpenVPN](https://openvpn.net/community-resources/reference-manual-for-openvpn-2-4/) web page. - -## What happens when establishing an OpenVPN connection? - -Every time I connect with OpenVPN I feel like R2-D2 hijacking their Starfleet plans. People don't always want to find themselves in deep scrutiny and may ask someone to explain to them what and how. In my purpose of writing this article, I actually asked myself this question and I put a lot of effort to get the answer. I don't want you to work so hard, but I can't say that you should upload it immediately, don't think about the rest, it's my job. As I promised at the beginning, I will explain this process to you in depth and leave the decision to you. Here's how the process works in an OpenVPN connection, pros and cons (as I've been able to figure it out so far). You first establish a TCP/UDP connection. You run a process like any application that uses TCP, and then you switch to the TLS layer. You are doing handshake and some authentication at TLS layer. This layer is also called the control channel. Then a certain communication is fixed and the data channel is passed. The process of encrypting and decrypting the data packets to be sent this time in the data or data channel begins. For this, devices are talking to each other and data is started to be sent under certain common conditions. In short, at the end of the process I have described in this way, the communication we started from 0 ends with the safe and desired data access to us, or requests are sent again, this time in a reverse way, over the connection that is kept open. Thus, a system like nested pipes emerges. If you need to write the only important thing required for the article here: - -- It will be `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P512`. - - Here the `TLS` input specifies that the control channel will be executed over the TLS layer. Other alternatives are `SSL` or `NULL`. - - The `ECDHE` input specifies that the first pre-key will be generated using the Elliptic Diffie-Hellman algorithm. Other alternatives are to use `DHE`, `DH` or not. - - The `ECDSA` data indicates that the Elliptic Digital Signature Certificate Algorithm will be used for mutual authentication and asymmetric key. Another available alternative is `RSA`. No need to count the others. - - Specifies the encryption algorithm to be used on the `AES_256_GCM` data channel. Other alternatives are `AES-128-CBC`, `AES-128-GCM` and `AES-256-CBC` - - `SHA384` specifies the hash algorithm to use. The other alternative is `SHA256`. - - `P512` allows the elliptic curve to be used to be selected as Prime-512. Other alternatives are `P-256` and `P-384`. - -### The process of establishing the TCP connection - -Now, if you have an approximate picture of the process in your mind, I start with the explanation of the TCP process. Let's say we have a client and a server in our case, and the connection is just these two. The client sends a SYN (m) packet to the server it wants to connect to. In response, the server sends a SYN (n) packet and an ACK (m+1) packet over the same port. The client that receives this also returns as ACK (n+1) in response, and a 3-way TCP handshake or 3-Way TCP handshake takes place. Thus, we have an open channel between client and server over the specified port. - -![https://blog.shiftasia.com/what-happen-when-access-website (Date: 08.04.2023)](/images/openvpn-full/TCP-Handshake.jpg) - ---- -![https://www.netscout.com/blog/asert/ddos-attacks-ssl-something-old-something-new (Date: 08.04.2023)](/images/openvpn-full/TCP-Handshake-2.png) - -As can be seen in the photos, if the process runs smoothly, communication can be made in 3 steps. But if you ask why we are doing this in 3 steps, can't it be done in a shorter way? I would say (for now) no, no, for a full-duplex communication, both parties need to send SYN and ACK packets. Maybe I'll tell you different ways in the future, but for now this is how it is. Anyway, the TCP/UDP part is always short and simple. - -### Process running in TLS layer - -After establishing a communication over TCP, the client is the person who takes the conversation to another level. Clients always request something from the server or request an answer. In general, servers are not seen to respond to a request that did not come to them. The process proceeds according to the principle of demand first, then supply. Yes, the parties are at the TLS layer now. The client first says hello to the server. Not a joke, it's real. The first packet sent by the client is called the `Client-Hello` packet. Next to this package (in order to speed up the process), the `Supported-Chipers` package that specifies the encryption algorithms it supports, a randomly generated number by the client, an `SNI` server name indicator if more than one service is running on the same IP address, and the session ID if necessary. . The server's response to this is, first of all, a polite hello. Because the first packet that the server sends in response is called the `Server-Hello` packet. Next to this package, the `Selected-Chiper` package, which specifies the server certificate, the encryption algorithms it supports, and the algorithm it chooses, sends a random number it generates, the Session ID if necessary, and an SNI-like ID if more than one client is connecting over the same IP. . The client first verifies with the server certificate whether it is really the person it is waiting for by starting the communication. In addition, in some cases, the server verifies with a certificate whether the client is one of the clients it expects. If this mutual-authentication process is positive, the next stage is passed. The key generation and exchange process is triggered. At this stage, the client again steps in and says that he wants to change the key with the algorithm they have determined during this communication, which is considered insecure. Parties begin to generate a prekey with Diffie-Hellman or ECDHE. For this, pre-secrets are shared by the client and server. The answers found by performing a number of mathematical operations are sent to the top and the same result is reached by performing mathematical operations again. The result is the first fore-key they've securely created between them. After that, with the encryption algorithm they determined, -A data channel other than the control channel is created to communicate and the process continues from there. - -![https://www.researchgate.net/publication/298065605_A_multi-level_framework_to_identify_HTTPS_services (Date: 08.04.2023)](/images/openvpn-full/TLS-Handshake.png) - ---- -![](/images/openvpn-full/TLS-Handshake-2.png) - -As can be seen in the photos, the process is almost the same as when connecting to a web page. Only certain stages are added, removed or changed according to needs. For example, in accordance with PFS, which stands for Advanced Privacy, the parties do not transmit the front-key with the server's asymmetric key. Because in this case, since the same key will be used for each session, the data will be stored and then the data will be readable retrospectively by waiting for a day when the key is revealed. That's why this change was made. Again, in accordance with the zero trust threat model, I want each layer and process to advance the process without trusting the other to do their job correctly. That's why we want the packets to be encrypted according to the `tls-auth` feature and to verify the integrity of the incoming and outgoing data, even at that first communication moment in the TLS layer. From the first moment you say hello, third parties will not be able to understand what you are talking about and at what stage you are. For this, the first communication is started with a predetermined key(s) and if necessary, these keys are renewed at regular intervals. Thus, even until the first pre-key is created in the TLS layer, confidentiality is not compromised and unauthorized parties are not created in vain. - -### Process running in the data layer - -If this whole process has been completed successfully and the data channel has been passed, you have now come to the best part of the job. Data will be encrypted with AES encryption method. During encryption, the tables will be shuffled according to the CBC-GCM counter mode according to your selection, and a 128 or 256-bit encryption key will be used in this process according to your selection. Of course, whatever you choose, the encryption block length will be 128 bits. Only the encryption key length changes. AES-256-GCM that I have chosen for this explanation is an AEAD encryption type. It summarizes the data it sends independently from other channels and processes at a certain stage and sends it together with the summary. Thus, authentication and encryption functions are fulfilled in AEAD, which stands for 'Authentication Encryption with associated data'. There is a problem that requires a distinction to be made here. At what stage and in which order will we use the encryption and hashing algorithms? - -|||| -|:---:|:---:|:---:| -| ![Encrypt-then-MAC (EtM)](/images/openvpn-full/EtM.png) | ![Encrypt-and-MAC (E-and-M)](/images/openvpn-full/EaM.png) | ![MAC-then-Encrypt (MtE)](/images/openvpn-full/MtE.png) | - -> https://en.wikipedia.org/wiki/Authenticated_encryption (Date: 08.04.2023) - -- According to EtM, which is the first approach, the data is first encrypted, then encrypted with another key as a result of the digest, and the resulting result is sent together in blocks. If we look at real-world solutions that use it, the IPSec protocol will come to mind first. This is the only method that can achieve the highest security definition in AE, but this can only be achieved if the MAC algorithm used is free of corruption or has not yet been cracked. Various EtM cipher suites are also available for SSHv2. Note, however, that key separation is mandatory for data and digest (different keys must be used for encryption and key hashing), otherwise you may end up with a potentially insecure result depending on the particular encryption method and hash function used. - -- According to the second approach, E&M, plain text data is encrypted and a summary of the encryption state of the plain text data is added next to it. Although only one key is used here, the fact that there are two different results (encryption result and digest result) for the same data clearly shows that the security is not good enough. As a real-world solution using this system, we can cite the first versions of SSH as an example. In order to improve this, methods such as encrypting the sent summary file with the same key were tried. - -- According to MtE, which is the third and last approach that I know of, a summary file is generated based on plain text. Then the plaintext and digest file together are encrypted with the key. The ciphertext and ciphertext file are sent together. If we look at real world solutions that use it, first and foremost are SSL/TLS implementations. We all know how reliable and sustainable SSL/TLS applications are in themselves. Beyond that, improvements such as `MAC-then-pad-then-encrypt` have been made over the years to increase security. According to this improvement, first the plain text is digested, then filled up to the block size, and then the encryption is done. This results in an even more reliable encryption result. But there are cases where the padding mechanism causes attacks like Padding Oracle if it makes certain mistakes. - -![https://community.openvpn.net/openvpn/wiki/Gigabit_Networks_Linux (Date: 08.04.2023)](/images/openvpn-full/TAP-TUN.png) - -After selecting the AEAD approach to be used, the path shown in the graphic above is followed according to the use of TAP or TUN. According to this path, the action done/desired to be done in the user area goes to TAP/TUN adapters at the kernel level. Because these adapters are at the kernel level, they operate very quickly. Then the virtual adapters do the necessary encryption with the relevant library, add the digest if necessary, and set the packet size. Then the server sends packets sequentially to the client's Ethernet interface over the Ethernet interface. The client that receives it reconfigures the packages, organizes them, combines them if necessary, and decrypts them with the necessary libraries. After decrypting it, it transmits the client to the end user via the virtual adapter. Thus, as a result of all these mathematical operations and efforts, after a few cycles, the user reached the desired content. It is quite long to explain, but very easy to use, dear readers. You just have to visit the relevant [script page](https://github.com/wiseweb-works/openvpn-most-secure-install/) on my GitHub page. The related script makes all these adjustments interactively for you. All you have to do is sit back and enjoy. - -# FAQ and End - -Received me via [mail](mailto:wisewebworks@outlook.com), [Fosstodon](https://fosstodon.org/@wise), or [GitHub](https://github.com/wiseweb-works) I will try to add questions here from time to time. Thus, historically, you will be able to reach the result directly without thinking about what kind of questions have arisen on which date or whether there is a solution. Apart from this, if there are questions that require extra explanation without changing the technical document, I think to include them in this section. +--- +title: "OpenVPN In-Depth Review" +date: 2022-03-27 +tags: ["linux", "ssl", "security", "ecc", "elliptic curve", "openvpn", "tls", "aes"] +author: "Wise" +draft: false +--- +# Introduction and Summary + +Today, we will make an in-depth review of OpenVPN, one of the most important software of recent times, in my opinion. In this review, we will first talk about what OpenVPN is used for. Then we will examine what we need to run the program and what needs to be done before the first run. Finally, I will try to explain what goes on in the background from the first moment the connection is started to the last step when the data is decrypted. Therefore, I guess our article will consist of 3 parts and a question-answer section if necessary. Now let's buckle up and take a trip to the deep and gloomy world of the internet. + +## What is OpenVPN and what is it used for? + +Today, there is almost no business that cannot be done online. Even our work, which is not normally online, has evolved to work from home due to the pandemic and the new normal. However, there were big problems both because it is a working method that we are not used to and because our people are not very good with technology. Before it became clear that people needed to connect from their home computers to their office computers, some companies came up with frivolous ideas such as sending office computers to employees' homes. They understood very well how wrong this was from the feedback they received in a short time. In short, it was finally accepted that electronic devices should remain in the office and somehow a secure and sustainable connection should be made remotely. Of course, institutions found themselves in such needs before, but such a large-scale situation was not in question back then. Before the pandemic, it used various protocols such as PPTP, L2TP, IPSec, IKev2, SSTP and finally OpenVPN. These are usually abbreviations for certain long and fancy words and their basic logic is to connect two or more devices and make them act as if they are on the same network. I won't talk much, as protocols prior to OpenVPN brought with them certain weaknesses, slowness, and technical difficulties with its implementation. OpenVPN is the name of the protocol and program that allows at least 2 devices in the role of server and client to connect to each other and do this in a way that meets industry standards. I'm using a remote desktop program, I seem to hear you say what is the need for this. Unfortunately, he and all other programs like him basically have to use this protocol. If you press the shield icon or the connection details in TeamViewer, one of the most famous, you can see the OpenVPN protocol. + +## What do we need to establish an OpenVPN connection? + +First of all, OpenVPN must be installed on both the server and client (the device to be connected) side. Then, a settings (config) file should be edited that shows the conditions under which the devices will communicate. The main event is that this config file is generated and used by the client. This config file is divided into server_config used by the server and client_config used by the client. + +### The settings file maintained by the server contains the following entries + +- `port 1194` specifies which port it will receive a connection request to make the OpenVPN connection. +- `proto tcp` Connection possible over TCP or UDP. Setting entry entered for selection. +- `dev tun` TAP or TUN interface can be used. These are virtual interfaces. TAP layer 2 establishes a connection, while TUN layer 3 establishes a connection. +- `user nobody` Enables connecting users to an unauthorized user on the server. +- `group $NOGROUP` It allows connecting users to be linked to an unauthorized group on the server as a group. +- `persist-key` An authorization setting for the creation and restart of the virtual interface +- `persist-tun` Also an authorization setting for the creation and restart of the virtual interface +- `keepalive 10 120` A setting for how many connections will be kept active and how long the active connection will be terminated if no communication is established. +- `ifconfig-pool-persist ipp.txt` A setting to keep the IP addresses given by OpenVPN to clients in the virtual network and give them the same addresses if they reconnect +- `push "dhcp-option DNS 1.1.1.1"` A DNS setting for the server to use when exiting the network +- `compress` The part where compression options are set +- `dh none` A setting for turning Diffie-Hellman on or off +- `ecdh-curve` If you are using Elliptic Curve Diffie-Hellman, the setting next to which the curve you need to select is adjusted +- `dh dh.pem` setting specifying the location of the PEM file you need to create beforehand if you are using Diffie-Hellman +- `tls-crypt tls-crypt.key` Required setting to encrypt TLS layer even before pre-shared master +- `tls-auth tls-auth.key 0` setting that allows parties to be authenticated beyond encryption at the pre-handshake stage of the TLS layer +- `crl-verify crl.pem` Setting to check whether the generated certificates are revoked or not via the CRL list +- `ca ca.crt` A setting that reports the location of the certificate of the certificate authority of the generated certificate +- `cert $SERVER_NAME.crt` A setting that tells the location of the server's certificate +- `key $SERVER_NAME.key` A setting indicating the location of the required asymmetric secret key next to the server's certificate +- `auth $HMAC_ALG` A setting describing which hash algorithm to use for the data channel and, if necessary, `tls-auth` +- `cipher $CIPHER` A setting that tells which encryption algorithm to use for the data channel +- `ncp-ciphers $CIPHER` A setting declaring which encryption algorithms the server can use +- `tls-server` A setting that tells the server to use the TLS channel +- A setting `tls-version-min 1.2` reports the lowest version to be used on the TLS channel +- `tls-cipher $CC_CIPHER` Encryption is also used at TLS layer, except for data channel, which is the setting declaring control channel encryption +- `client-config-dir /etc/openvpn/ccd` Setting that tells where client settings files are kept +- `status /var/log/openvpn/status.log` Setting that tells where status reports are written and where log files are kept +- `verb 3` This setting, which is the abbreviation of the word Verbose, is the setting of how detailed the status report is to be given. + +### The client-side settings file contains the following entries + +- `client` indicates that the device is in the client role +- `proto tcp-client` reports to use TCP as protocol +- `remote $IP $PORT` The part where the IP address and Port number of the server(s) to be connected are set +- `dev tun` sets which of the TUN/TAP interfaces to use +- `resolve-retry infinite` We tell you how long to wait if address resolution is delayed due to IP or DNS +- `nobind` setting to not connect to any address in the local +- `persist-key` Allows key files to be read without additional authorization on reboot +- `persist-tun` It also allows the TUN/TAP interface to be woken up without authorization on reboot +- `remote-cert-tls server` Verifies the certificate of the connected server at TLS layer +- `verify-x509-name $SERVER_NAME name` Command that tells the name in the certificate that the server will return to and what the name of the server should be +- `auth $HMAC_ALG` Command that tells which algorithm to use for validation +- `auth-nocache` Does not cache the password required for login +- `cipher $CIPHER` Command to select the algorithm to be used for encryption +- `tls-client` enables TLS during TLS communication and assumes the client role +- `tls-version-min 1.2` Sets the lowest TLS version +- `tls-cipher $CC_CIPHER` selects the encryption algorithm to use in the TLS control channel +- `ignore-unknown-option block-outside-dns` Prevents unknown DNS addresses from being used +- `setenv opt block-outside-dns` blocks DNS leaks for Windows 10 +- `verb 3` Determines the degree of reporting +- `compress` Compression algorithm settings are reported here +- `"/etc/openvpn/easy-rsa/pki/ca.crt"` Hard-Coded embedding of expected server certificate authority file +- `"/etc/openvpn/easy-rsa/pki/issued/$CLIENT.crt"` Hard-Coded embedding of client certificate file +- `"/etc/openvpn/easy-rsa/pki/private/$CLIENT.key"` Hard-Coded embedding of client asymmetric secret key +- `"/etc/openvpn/tls-crypt.key"` Specifying the key file for TLS crypt +- `"/etc/openvpn/tls-auth.key"` Specifying the key file for TLS auth +- `key-direction 1` assigns roles to client and server for TLS layer encryption (0 and 1) + +You can find detailed documentation of these settings and more on the [OpenVPN](https://openvpn.net/community-resources/reference-manual-for-openvpn-2-4/) web page. + +## What happens when establishing an OpenVPN connection? + +Every time I connect with OpenVPN I feel like R2-D2 hijacking their Starfleet plans. People don't always want to find themselves in deep scrutiny and may ask someone to explain to them what and how. In my purpose of writing this article, I actually asked myself this question and I put a lot of effort to get the answer. I don't want you to work so hard, but I can't say that you should upload it immediately, don't think about the rest, it's my job. As I promised at the beginning, I will explain this process to you in depth and leave the decision to you. Here's how the process works in an OpenVPN connection, pros and cons (as I've been able to figure it out so far). You first establish a TCP/UDP connection. You run a process like any application that uses TCP, and then you switch to the TLS layer. You are doing handshake and some authentication at TLS layer. This layer is also called the control channel. Then a certain communication is fixed and the data channel is passed. The process of encrypting and decrypting the data packets to be sent this time in the data or data channel begins. For this, devices are talking to each other and data is started to be sent under certain common conditions. In short, at the end of the process I have described in this way, the communication we started from 0 ends with the safe and desired data access to us, or requests are sent again, this time in a reverse way, over the connection that is kept open. Thus, a system like nested pipes emerges. If you need to write the only important thing required for the article here: + +- It will be `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P512`. + - Here the `TLS` input specifies that the control channel will be executed over the TLS layer. Other alternatives are `SSL` or `NULL`. + - The `ECDHE` input specifies that the first pre-key will be generated using the Elliptic Diffie-Hellman algorithm. Other alternatives are to use `DHE`, `DH` or not. + - The `ECDSA` data indicates that the Elliptic Digital Signature Certificate Algorithm will be used for mutual authentication and asymmetric key. Another available alternative is `RSA`. No need to count the others. + - Specifies the encryption algorithm to be used on the `AES_256_GCM` data channel. Other alternatives are `AES-128-CBC`, `AES-128-GCM` and `AES-256-CBC` + - `SHA384` specifies the hash algorithm to use. The other alternative is `SHA256`. + - `P512` allows the elliptic curve to be used to be selected as Prime-512. Other alternatives are `P-256` and `P-384`. + +### The process of establishing the TCP connection + +Now, if you have an approximate picture of the process in your mind, I start with the explanation of the TCP process. Let's say we have a client and a server in our case, and the connection is just these two. The client sends a SYN (m) packet to the server it wants to connect to. In response, the server sends a SYN (n) packet and an ACK (m+1) packet over the same port. The client that receives this also returns as ACK (n+1) in response, and a 3-way TCP handshake or 3-Way TCP handshake takes place. Thus, we have an open channel between client and server over the specified port. + +![https://blog.shiftasia.com/what-happen-when-access-website (Date: 08.04.2023)](/images/openvpn-full/TCP-Handshake.jpg) + +--- +![https://www.netscout.com/blog/asert/ddos-attacks-ssl-something-old-something-new (Date: 08.04.2023)](/images/openvpn-full/TCP-Handshake-2.png) + +As can be seen in the photos, if the process runs smoothly, communication can be made in 3 steps. But if you ask why we are doing this in 3 steps, can't it be done in a shorter way? I would say (for now) no, no, for a full-duplex communication, both parties need to send SYN and ACK packets. Maybe I'll tell you different ways in the future, but for now this is how it is. Anyway, the TCP/UDP part is always short and simple. + +### Process running in TLS layer + +After establishing a communication over TCP, the client is the person who takes the conversation to another level. Clients always request something from the server or request an answer. In general, servers are not seen to respond to a request that did not come to them. The process proceeds according to the principle of demand first, then supply. Yes, the parties are at the TLS layer now. The client first says hello to the server. Not a joke, it's real. The first packet sent by the client is called the `Client-Hello` packet. Next to this package (in order to speed up the process), the `Supported-Chipers` package that specifies the encryption algorithms it supports, a randomly generated number by the client, an `SNI` server name indicator if more than one service is running on the same IP address, and the session ID if necessary. . The server's response to this is, first of all, a polite hello. Because the first packet that the server sends in response is called the `Server-Hello` packet. Next to this package, the `Selected-Chiper` package, which specifies the server certificate, the encryption algorithms it supports, and the algorithm it chooses, sends a random number it generates, the Session ID if necessary, and an SNI-like ID if more than one client is connecting over the same IP. . The client first verifies with the server certificate whether it is really the person it is waiting for by starting the communication. In addition, in some cases, the server verifies with a certificate whether the client is one of the clients it expects. If this mutual-authentication process is positive, the next stage is passed. The key generation and exchange process is triggered. At this stage, the client again steps in and says that he wants to change the key with the algorithm they have determined during this communication, which is considered insecure. Parties begin to generate a prekey with Diffie-Hellman or ECDHE. For this, pre-secrets are shared by the client and server. The answers found by performing a number of mathematical operations are sent to the top and the same result is reached by performing mathematical operations again. The result is the first fore-key they've securely created between them. After that, with the encryption algorithm they determined, +A data channel other than the control channel is created to communicate and the process continues from there. + +![https://www.researchgate.net/publication/298065605_A_multi-level_framework_to_identify_HTTPS_services (Date: 08.04.2023)](/images/openvpn-full/TLS-Handshake.png) + +--- +![](/images/openvpn-full/TLS-Handshake-2.png) + +As can be seen in the photos, the process is almost the same as when connecting to a web page. Only certain stages are added, removed or changed according to needs. For example, in accordance with PFS, which stands for Advanced Privacy, the parties do not transmit the front-key with the server's asymmetric key. Because in this case, since the same key will be used for each session, the data will be stored and then the data will be readable retrospectively by waiting for a day when the key is revealed. That's why this change was made. Again, in accordance with the zero trust threat model, I want each layer and process to advance the process without trusting the other to do their job correctly. That's why we want the packets to be encrypted according to the `tls-auth` feature and to verify the integrity of the incoming and outgoing data, even at that first communication moment in the TLS layer. From the first moment you say hello, third parties will not be able to understand what you are talking about and at what stage you are. For this, the first communication is started with a predetermined key(s) and if necessary, these keys are renewed at regular intervals. Thus, even until the first pre-key is created in the TLS layer, confidentiality is not compromised and unauthorized parties are not created in vain. + +### Process running in the data layer + +If this whole process has been completed successfully and the data channel has been passed, you have now come to the best part of the job. Data will be encrypted with AES encryption method. During encryption, the tables will be shuffled according to the CBC-GCM counter mode according to your selection, and a 128 or 256-bit encryption key will be used in this process according to your selection. Of course, whatever you choose, the encryption block length will be 128 bits. Only the encryption key length changes. AES-256-GCM that I have chosen for this explanation is an AEAD encryption type. It summarizes the data it sends independently from other channels and processes at a certain stage and sends it together with the summary. Thus, authentication and encryption functions are fulfilled in AEAD, which stands for 'Authentication Encryption with associated data'. There is a problem that requires a distinction to be made here. At what stage and in which order will we use the encryption and hashing algorithms? + +|||| +|:---:|:---:|:---:| +| ![Encrypt-then-MAC (EtM)](/images/openvpn-full/EtM.png) | ![Encrypt-and-MAC (E-and-M)](/images/openvpn-full/EaM.png) | ![MAC-then-Encrypt (MtE)](/images/openvpn-full/MtE.png) | + +> https://en.wikipedia.org/wiki/Authenticated_encryption (Date: 08.04.2023) + +- According to EtM, which is the first approach, the data is first encrypted, then encrypted with another key as a result of the digest, and the resulting result is sent together in blocks. If we look at real-world solutions that use it, the IPSec protocol will come to mind first. This is the only method that can achieve the highest security definition in AE, but this can only be achieved if the MAC algorithm used is free of corruption or has not yet been cracked. Various EtM cipher suites are also available for SSHv2. Note, however, that key separation is mandatory for data and digest (different keys must be used for encryption and key hashing), otherwise you may end up with a potentially insecure result depending on the particular encryption method and hash function used. + +- According to the second approach, E&M, plain text data is encrypted and a summary of the encryption state of the plain text data is added next to it. Although only one key is used here, the fact that there are two different results (encryption result and digest result) for the same data clearly shows that the security is not good enough. As a real-world solution using this system, we can cite the first versions of SSH as an example. In order to improve this, methods such as encrypting the sent summary file with the same key were tried. + +- According to MtE, which is the third and last approach that I know of, a summary file is generated based on plain text. Then the plaintext and digest file together are encrypted with the key. The ciphertext and ciphertext file are sent together. If we look at real world solutions that use it, first and foremost are SSL/TLS implementations. We all know how reliable and sustainable SSL/TLS applications are in themselves. Beyond that, improvements such as `MAC-then-pad-then-encrypt` have been made over the years to increase security. According to this improvement, first the plain text is digested, then filled up to the block size, and then the encryption is done. This results in an even more reliable encryption result. But there are cases where the padding mechanism causes attacks like Padding Oracle if it makes certain mistakes. + +![https://community.openvpn.net/openvpn/wiki/Gigabit_Networks_Linux (Date: 08.04.2023)](/images/openvpn-full/TAP-TUN.png) + +After selecting the AEAD approach to be used, the path shown in the graphic above is followed according to the use of TAP or TUN. According to this path, the action done/desired to be done in the user area goes to TAP/TUN adapters at the kernel level. Because these adapters are at the kernel level, they operate very quickly. Then the virtual adapters do the necessary encryption with the relevant library, add the digest if necessary, and set the packet size. Then the server sends packets sequentially to the client's Ethernet interface over the Ethernet interface. The client that receives it reconfigures the packages, organizes them, combines them if necessary, and decrypts them with the necessary libraries. After decrypting it, it transmits the client to the end user via the virtual adapter. Thus, as a result of all these mathematical operations and efforts, after a few cycles, the user reached the desired content. It is quite long to explain, but very easy to use, dear readers. You just have to visit the relevant [script page](https://github.com/wiseweb-works/openvpn-most-secure-install/) on my GitHub page. The related script makes all these adjustments interactively for you. All you have to do is sit back and enjoy. + +# FAQ and End + +Received me via [mail](mailto:wisewebworks@outlook.com), [Fosstodon](https://fosstodon.org/@wise), or [GitHub](https://github.com/wiseweb-works) I will try to add questions here from time to time. Thus, historically, you will be able to reach the result directly without thinking about what kind of questions have arisen on which date or whether there is a solution. Apart from this, if there are questions that require extra explanation without changing the technical document, I think to include them in this section. diff --git a/content/post/openvpn-full-anlatim.md b/content/post/openvpn-full-anlatim.md index 20084064..4057c724 100644 --- a/content/post/openvpn-full-anlatim.md +++ b/content/post/openvpn-full-anlatim.md @@ -1,140 +1,140 @@ ---- -title: "OpenVPN Derinlemesine Anlatım" -date: 2022-03-27 -tags: ["linux", "ssl", "security", "ecc", "elliptic curve", "openvpn", "tls", "aes"] -author: "Wise" -draft: false ---- -# Giriş ve Özet - -Bugün sizlerle kendi bence son zamanların en önemli yazılımlarından olan OpenVPN ile ilgili derinlemesine bir inceleme yapacağız. Bu incelememizde öncelikle OpenVPN'in ne için kullanıldığından bahsedeceğiz. Ardından programı çalıştırmak için nelere ihtiyaç duyduğumuzu ve ilk çalıştırma öncesi yapılması gerekenleri inceleyeceğiz. Son olarak da bağlantının başlatıldığı ilk andan verinin çözüldüğü son adıma kadar nelerin arka planda döndüğünü anlatmaya çalışacağım. Dolayısıyla yazımız tahminimce 3 bölüm ve gerekirse bir de soru-cevap bölümünden oluşacak. Şimdi kemerlerimizi bağlayalım ve internetin derin ve kasvetli dünyasında bir geziye çıkalım. - -## OpenVPN nedir ve ne için kullanılıyor ? - -Günümüzde artık internet üzerinden yapılmayan bir iş neredeyse kalmadı. Hatta normalde internet üzerinden olmayan çalışma eylemimiz bile pandemi ve yeni normal nedeniyle evden çalışmaya doğru evrildi. Fakat hem alışık olmadığımız bir çalışma yöntemi olması nedeniyle hem de insanlarımızın teknoloji ile arasının pek iyi olmaması nedeniyle büyük sorunlar yaşandı. İnsanların evlerindeki bilgisayarlardan ofisteki bilgisayarlarına bağlanması gerektiği anlaşılmadan önce bazı firmalar çalışanların evlerine ofis bilgisayarlarını gönderme gibi uçuk fikirler buldu. Bunun ne kadar hatalı bir gidiş yolu olduğunu kısa süre içinde aldıkları geri dönüşlerden çok iyi anladılar. Kısaca elektronik cihazların ofiste kalması ve bir şekilde uzaktan güvenli ve sürdürülebilir bir bağlantı yapılması gerektiği sonunda kabullenildi. Kurumlar daha önceleri de kendilerini böyle ihtiyaçlar içinde buluyordu elbette ama bu derece büyük ölçekli bir durum söz konusu değildi o zamanlar. Pandemi öncesinde PPTP, L2TP, IPSec, IKev2, SSTP ve nihayet OpenVPN gibi çeşitli protokoller kullanıyordu. Bunlar genelde belirli uzun ve havalı kelimelerin kısaltması olup temel mantıkları iki veya daha fazla cihazı birbirine bağlamak ve aynı ağdaymış gibi hareket etmelerini sağlamak üzerinedir. OpenVPN'den önceki protokoller belirli zayıflıkları, yavaşlıkları ve uygulanmasıyla ilgili teknik zorlukları da beraberlerinde getirdikleri için çok bahsetmeyeceğim. OpenVPN sunucu ve istemci rolündeki en az 2 cihazın birbirlerine bağlanması ve bunu endüstiri standartlarını karşılayacak şekilde yapmasına yarayan protokol ve programın adıdır. Ben uzak masaüstü programı kullanıyorum buna ne gerek var dediğinizi duyar gibiyim. Maalesef o ve onun gibi diğer tüm programlar temelde bu protokolü kullanmak durumunda kalıyorlar. En meşhurlarından olan TeamViewer programında kalkan simgesine veya bağlantı ayrıntılarına bastığınız takdirde OpenVPN protokolünü görebilirsiniz. - -## OpenVPN bağlantısı kurmak için nelere ihtiyaç duyarız ? - -Öncelikle hem sunucu hem de istemci (bağlanacak cihaz) tarafında OpenVPN'in kurulu olması gerekiyor. Ardından cihazların hangi şartlar altında iletişim kuracaklarını gösterir bir ayar (config) dosyasının düzenlenmesi gerekmektedir. Asıl olay zaten bu config dosyasının üretilmesi ve istemci tarafından kullanılmasıdır. Bu config dosyası sunucu tarafından kullanılan server_config ve istemci tarafından kullanılan client_config olarak ikiye ayrılır. - -### Server tarafında tutulan ayar dosyası şu girdileri içermektedir - -- `port 1194` OpenVPN bağlantısını yapmak için kendisine hangi port üzerinden bağlantı talebi geleceğini belirtir. -- `proto tcp` Bağlantının TCP veya UDP üzerinden yapılması mümkün. Seçim için girilen ayar girdisi. -- `dev tun` TAP veya TUN arabirimi kullanılabilir. Bunlar sanal arabirimlerdir. TAP layer 2 bir bağlantı kurarken TUN layer 3 bir bağlantı kurar. -- `user nobody` Bağlanan kullanıcıların sunucu üzerinde yetkisiz bir kullanıcıya linklenmesini sağlıyor. -- `group $NOGROUP` Bağlanan kullanıcıların sunucu üzerinde grup olarak da yetkisiz bir gruba linklenmesini sağlıyor. -- `persist-key` Sanal arabirimin oluşturulması ve yeniden başlatılması ile ilgili bir yetkilendirme ayarı -- `persist-tun` Yine aynı şekilde sanal arabirimin oluşturulması ve yeniden başlatılması ile ilgili bir yetkilendirme ayarı -- `keepalive 10 120` Kaç adet bağlantının aktif tutulacağını ve ne kadar süre iletişim kurulmaz ise aktif bağlantının sonlandırılacağı ile ilgili bir ayar -- `ifconfig-pool-persist ipp.txt` OpenVPN tarafından istemcilere sanal ağda verilen IP adreslerinin tutulması ve tekrar bağlandıkları takdirde aynı adreslerin verilmesi için bir ayar -- `push "dhcp-option DNS 1.1.1.1"` Sunucunun ağa çıkarken kullanması için bir DNS ayarı -- `compress` Sıkıştırma seçeneklerinin ayarlandığı kısım -- `dh none` Diffie-Hellman'ın açılıp kapatılması ile ilgili bir ayar -- `ecdh-curve` Eğer Elliptik Eğri Diffie-Hellman kullanıyor iseniz yanında seçmeniz gereken eğrinin ayarlandığı ayar -- `dh dh.pem` Diffie-Hellman kullanıyor iseniz önceden oluşturmanız gereken PEM dosyasının konumunu belirten ayar -- `tls-crypt tls-crypt.key` TLS katmanının pre-shared master öncesinde dahi şifrelenmesi için gerekli ayar -- `tls-auth tls-auth.key 0` TLS katmanının pre-handshake aşamasında şifrelenmesinin de ötesinde tarafların da doğrulanmasını sağlayan ayar -- `crl-verify crl.pem` Üretilen sertifikaların revoke edilip edilmediğinin CRL listesi üzerinden kontrol edilmesine yarayan ayar -- `ca ca.crt` Üretilen sertifikaya ait sertifika otoritesinin sertifikasının konumunu bildiren bir ayar -- `cert $SERVER_NAME.crt` Sunucunun sertifikasının konumunu bildiren bir ayar -- `key $SERVER_NAME.key` Sunucunun sertifikasının yanında yine gerekli olan asimetrik secret keyinin konumunu bildiren bir ayar -- `auth $HMAC_ALG` Veri kanalı ve gerekirse `tls-auth` için hangi özet algoritmasının kullanılacağını bildiren bir ayar -- `cipher $CIPHER` Veri kanalı için hangi şifreleme algoritmasının kullanılacağını bildiren bir ayar -- `ncp-ciphers $CIPHER` Sunucunun kullanabileceği şifreleme algoritmalarını bildiren bir ayar -- `tls-server` Sunucunun TLS kanalını kullanmasını söyleyen bir ayar -- `tls-version-min 1.2` TLS kanalında kullanılması için en düşük versiyonu bildiren bir ayar -- `tls-cipher $CC_CIPHER` Veri kanalından hariç TLS katmanında da şifreleme kullanılıyor bu da kontrol kanalı şifrelemesini bildiren ayar -- `client-config-dir /etc/openvpn/ccd` İstemci ayar dosyalarının tutulduğu konumu bildiren ayar -- `status /var/log/openvpn/status.log` Durum raporlarının yazılacağı konumu ve log dosyalarının tutulduğu konumu bildiren ayar -- `verb 3` Verbose kelimesinin kısaltılmışı olan bu ayar ne kadar detaylı durum raporu verileceğinin ayarıdır. - -### İstemci tarafında tutulan ayar dosyası şu girdileri içermektedir - -- `client` İlgili cihazın istemci rolünde olduğunu belirtiyor -- `proto tcp-client` Protokol olarak TCP'nin kullanılacağını bildiriyor -- `remote $IP $PORT` Bağlanılacak sunucu(ların) IP adresinin ve Port numarasının ayarladığı kısım -- `dev tun` TUN/TAP arabirimlerinden hangisinin kullanılacağını ayarlıyor -- `resolv-retry infinite` Eğer IP veya DNS nedeniyle adres çözümlemesi gecikir ise ne kadar süre ile bekleyeceğini söylüyoruz -- `nobind` Lokaldeki herhangi bir adrese bağlanılmamasını bildiren ayar -- `persist-key` Yeniden başlatma durumunda anahtar dosyalarının ek bir yetkiye gerek kalmadan okunabilmesini yarar -- `persist-tun` Aynı şekilde yeniden başlatma durumunda TUN/TAP arabiriminin yetkiye gerek kalmadan uyandırılabilmesine yarar -- `remote-cert-tls server` Bağlanılan sunucunun sertifikasını TLS katmanında doğrulanmasını sağlar -- `verify-x509-name $SERVER_NAME name` Sunucunun geri döneceği sertifikasındaki ismi ve sunucunun isminin ne olması gerektiğini bildiren komut -- `auth $HMAC_ALG` Doğrulama için hangi algoritmanın kullanılacağını bildiren komut -- `auth-nocache` Oturum açmak için gerekli parolayı önbelleğe almaz -- `cipher $CIPHER` Şifreleme için kullanılacak algoritmayı seçmeye yarayan komut -- `tls-client` TLS iletişimi sırasında TLS'yi etkinleştirir ve istemci rolünü üstlenir -- `tls-version-min 1.2` En düşük TLS versiyonunu ayarlar -- `tls-cipher $CC_CIPHER` TLS kontrol kanalında kullanılacak şifreleme algoritmasını seçer -- `ignore-unknown-option block-outside-dns` Bilinmeyen DNS adreslerinin kullanılmasını engeller -- `setenv opt block-outside-dns` Windows 10 için DNS sızıntılarını engeller -- `verb 3` Rapor verme derecesini belirler -- `compress` Sıkıştırma algoritması ayarları burada bildirilir -- `"/etc/openvpn/easy-rsa/pki/ca.crt"` Beklenilen sunucu sertifika otoritesi dosyasının Hard-Coded gömülmesi -- `"/etc/openvpn/easy-rsa/pki/issued/$CLIENT.crt"` İstemci sertifika dosyasının Hard-Coded gömülmesi -- `"/etc/openvpn/easy-rsa/pki/private/$CLIENT.key"` İstemci asimetrik secret keyinin Hard-Coded gömülmesi -- `"/etc/openvpn/tls-crypt.key"` TLS crypt için key dosyasının belirtilmesi -- `"/etc/openvpn/tls-auth.key"` TLS auth için key dosyasının belirtilmesi -- `key-direction 1` TLS katmanı şifrelenmesi için istemci ve sunucuya rol atıyor (0 ve 1 şeklinde) - -Bu ayarları ve daha bir çoğunun ayrıntılı dökümantasyonunu [OpenVPN](https://openvpn.net/community-resources/reference-manual-for-openvpn-2-4/) web sayfasında bulabilirsiniz. - -## OpenVPN bağlantısı kurulurken neler oluyor ? - -OpenVPN ile bağlantı kurduğum her zaman kendimi Yıldız Filosu planlarını kaçıran R2-D2 gibi hissediyorum. İnsanlar kendilerini her zaman için derinlemesine bir inceleme içerisinde bulmak istemiyorlar ve birilerinin onlara neyin nasıl döndüğünü açıklamalarını isteyebiliyorlar. Benim bu yazıyı kaleme alma amacımda aslında bu soruyu kendime sormuş olmam ve cevabını almak için çok çaba sarfetmiş olmam. Sizin de bu kadar uğraşmanızı istemem fakat size hemencecik bunu yükle gerisini düşünme o iş bende de diyemem. Başta söz verdiğim gibi derinlemesine bir şekilde bu süreci sizlere anlatacağım ve kararı size bırakacağım. Bir OpenVPN bağlantısında artısıyla eksisiyle (benim şu ana kadar çözebildiğim şekliyle) süreç şöyle işliyor. Önce bir TCP/UDP bağlantısı kuruyorsunuz. TCP kullanan her uygulama gibi bir süreç yürütüyorsunuz ve ardından TLS katmanına geçiyorsunuz. TLS katmanında el sıkışma (handshake) ve bazı kimlik doğrulama işlemleri yapıyorsunuz. Bu katmana aynı zamanda kontrol kanalı da deniliyor. Ardından belirli bir iletişim tutturulmuş oluyor ve veri kanalına geçiliyor. Veri veya data kanalında bu sefer gönderilecek veri paketlerinin şifrelenmesi ve çözülmesi süreci başlıyor. Bunun için yine cihazlar birbirleri ile konuşuyor ve belirli ortak şartlar altında veriler gönderilmeye başlanıyor. Kısaca bu şekilde anlattığım sürecin sonunda 0'dan başlattığımız iletişim bize güvenli ve istediğimiz şekilde verilerin ulaşması ile son buluyor veya açık tutulan bağlantı üzerinden bu sefer tersine bir yolla yeniden istekler iletiliyor. Böylece iç içe borular gibi bir sistem ortaya çıkıyor. Yazı için gerekli olan tek önemli şeyi buraya yazmak gerekirse eğer: - -- `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P512` şeklinde olacaktır. - - Burada `TLS` girdisi kontrol kanalının TLS katmanı üzerinden yürütüleceğini belirtir. Diğer alternatifler `SSL` veya `NULL`'dur. - - `ECDHE` girdisi Elliptik Diffie-Hellman algoritması kullanılarak ilk ön-anahtarın üretileceğini belirtir. Diğer alternatifler `DHE`, `DH` veya kullanmamaktır. - - `ECDSA` verisi karşılıklı kimlik doğrulama ve asimetrik anahtar için Elliptik Dijital İmza Sertifikası Algoritmasının kullanılacağını belirtir. Diğer kullanılabilir alternatif `RSA`'dır. Diğerlerini saymaya gerek bile yok. - - `AES_256_GCM` veri kanalında kullanılacak şifreleme algoritmasının belirtir. Diğer alternatifler `AES-128-CBC`, `AES-128-GCM` ve `AES-256-CBC`'dir - - `SHA384` kullanılacak özet algoritmasını belirtir. Diğer alternatif `SHA256`'dır. - - `P512` ise kullanılacak elliptik eğrinin Prime-512 adlı eğri olarak seçilmesini sağlar. Diğer alternatifler `P-256` ve `P-384`'dür. - -### TCP bağlantısının kurulması süreci - -Şimdi kafanızda sürecin yaklaşık bir resmi oluştu ise başlangıcı TCP sürecinin anlatımıyla yapıyorum. Olayımızda bir istemci ve bir sunucunun olduğunu ve bağlantının sadece bu ikisinden ibaret olduğunu düşünelim. İstemci bağlanmak istediği sunucuya bir SYN (m) paketi gönderir. Sunucu ise buna cevap olarak aynı port üzerinden bir SYN (n) paketi ve ACK (m+1) paket gönderir. Bunu alan istemci de cevap olarak ACK (n+1) şeklinde dönüş yapar ve 3'lü TCP el sıkışması veya 3 Way TCP handshake gerçekleşmiş olur. Böylece belirtilen port üzerinden istemci ve sunucu arasında açık bir kanalımız oluştu. - -![https://blog.shiftasia.com/what-happen-when-access-website (Erişim Tarihi: 08.04.2023)](/images/openvpn-full/TCP-Handshake.jpg) - ---- -![https://www.netscout.com/blog/asert/ddos-attacks-ssl-something-old-something-new (Erişim Tarihi: 08.04.2023)](/images/openvpn-full/TCP-Handshake-2.png) - -Fotoğraflarda da görüleceği üzere eğer süreç sorunsuz işler ise 3 adımda iletişim kurulabiliyor. Fakat neden 3 adımda bu işi yapıyoruz daha kısa şekilde olmaz mı derseniz size (şimdilik) hayır olmaz full-duplex bir iletişim için her iki tarafın da SYN ve ACK paketlerini göndermesi gerekiyor derim. İleride belki farklı yollarını da anlatırım ama şimdilik böyle. Zaten işin TCP/UDP kısmı her zaman için kısa ve basittir. - -### TLS katmanındaki işletilen süreç - -TCP üzerinden bir iletişim kurulmasının ardından yine muhabbeti başka bir aşamaya taşıyan kişi istemci oluyor. Her zaman için istemciler sunucudan bir şeyler talep eder veya bir cevap ister. Sunucular genel olarak kendilerine gelmeyen bir isteği cevapladığı çok görülmemiştir. Önce talep sonra arz ilkesine göre süreç ilerler. Evet, taraflar TLS katmanındalar şimdi. İstemci sunucuya önce bir merhaba diyor. Şaka değil gerçek. İstemci tarafından gönderilen ilk pakete `Client-Hello` paketi denir. Bu paketin yanında (süreci hızlandırmak adına) desteklediği şifreleme algoritmalarını belirten `Supported-Chipers` paketi, istemci tarafından rastgele üretilmiş bir sayı, aynı IP adresinde birden fazla hizmet çalıştırılıyor ise bir `SNI` sunucu adı indikatörü ve yine gerekiyor ise oturum ID'si gönderilir. Sunucunun buna cevabı ise öncelikle kibar bir merhaba demek oluyor. Çünkü sunucunun cevaben gönderdiği ilk pakete de `Server-Hello` paketi denir. Bu paketin yanında sunucu sertifikasını, kendi desteklediği şifreleme algoritmalarını ve seçtiği algoritmayı belirten `Selected-Chiper` paketi, kendisinin ürettiği rastgele bir sayıyı, gerekirse Oturum ID'sini ve aynı IP üzerinden birden fazla istemci bağlanıyor ise buna ilişkin SNI benzeri bir ID'yi gönderir. İstemci öncelikle iletişime başladığı tarafından gerçekten beklediği kişi olup olmadığını sunucu sertifikası ile doğrular. Ayrıca bazı durumlarda da sunucu istemcinin beklediği istemcilerden biri olup olmadığını yine sertifika ile doğrular. Eğer bu karşılıklı doğrulama (mutual-authentication) süreci olumlu sonuçlanır ise bir sonraki aşamaya geçilir. Anahtar üretim ve değişim süreci tetiklenmiş olur. Bu aşamda yine istemci devreye girer ve güvensiz önkabul edilen bu iletişim sırasında belirledikleri algoritma ile anahtar değiştirmek istediğini söyler. Taraflar Diffie-Hellman veya ECDHE ile bir önanahtar oluşturmaya başlarlar. Bunun için istemci ve sunucu tarafından ön-sırlar paylaşılır. Bir takım matematiksel işlemler yapılarak bulunan cevaplar karşıya gönderilir ve tekrar matematiksel işlemler yapılarak aynı sonuca ulaşılır. İşte ulaşılan sonuç aralarında güvenli bir şekilde oluşturdukları ilk ön-anahtar oluyor. Bundan sonra belirledikleri şifreleme algoritması ile -iletişime geçmek için kontrol kanalından hariç bir veri kanalı oluşturulur ve süreç oradan devam eder. - -![https://www.researchgate.net/publication/298065605_A_multi-level_framework_to_identify_HTTPS_services (Erişim Tarihi: 08.04.2023)](/images/openvpn-full/TLS-Handshake.png) - ---- -![](/images/openvpn-full/TLS-Handshake-2.png) - -Fotoğraflarda da görülebileceği üzere süreç bir web sayfasına bağlanılırken yaşanan süreçle neredeyse aynı. Sadece ihtiyaçlara göre belirli aşamalar ekleniyor, çıkarılıyor veya değiştiriliyor. Örneğin İleri Seviye Gizlilik anlamına gelen PFS gereğince taraflar ön-anahtarı sunucunun asimetrik anahtarı ile iletmiyor. Çünkü bu durumda her oturum için aynı anahtar kullanılacağı için verilerin depolanıp daha sonra anahtar açığa çıktığı bir gün beklenerek veriler geçmişe dönük okunabilir bir hale gelecektir. Bu yüzden bu değişiklik yapıldı. Yine sıfır güven tehdit modeli gereğince her bir katmanın ve sürecin bir diğerinin işini doğru yapacağına güvenmeden süreci ilerletmesini istiyorum. Bu yüzden TLS katmanındaki o ilk iletişim anında dahi paketlerin `tls-auth` özelliği gereğince şifrelenmesini ve gelen-giden verilerin bütünlüğünün doğrulanmasını istiyoruz. Daha ilk merhaba dediğiniz andan itibaren üçüncü kişiler sizin ne konuştuğunuzu hangi aşamada olduğunuzu anlayamayacaklardır. Bunun için önceden belirlenmiş bir anahtar/anahtarlar ile ilk iletişim başlatılır ve gerekirse belirli aralıklarla bu anahtarlar yenilenir. Böylece TLS katmanında ilk ön-anahtar oluşturulana kadar dahi gizlilikten ödün verilmemiş ve yetkisiz kişilerce boşuna tarafik yaratılmamış olur. - -### Veri katmanında işleyen süreç - -Eğer tüm bu süreç başarılı bir şekilde tamamlanmış ve veri kanalına geçilebildiyse eğer artık işin en güzel kısmına gelmiş bulunuyorsunuz. Veriler AES şifreleme methodu ile şifrelenecek. Şifreleme sırasında seçiminize göre CBC-GCM counter moduna göre tablolar karıştırılacak ve bu süreçte seçiminize göre 128 veya 256 bit uzunluğunda şifreleme anahtarı kullanılacak. Tabi ne hangisini seçerseniz seçin şifreleme blok uzunluğu 128 bit olucak. Değişen sadece şifreleme anahtarı uzunluğu. Benim bu anlatımım için seçmiş olduğum AES-256-GCM bir AEAD şifreleme türüdür. Diğer kanallardan ve süreçlerden bağımsız olarak gönderdiği verileri belirli bir aşamada özetini çıkartır ve özeti ile birlikte gönderir. Böylece 'Authentication Encryption with associated data' anlamına gelen AEAD'de doğrulama ve şifreleme işlevleri yerine getirilmiş oluyor. Burada bir ayrıma gidilmesini gerektirecek şöyle bir sorun mevcuttur. Şifreleme ve Özet alma algoritmalarını hangi aşamada ve sırayla kullanacağız. - -|||| -|:---:|:---:|:---:| -| ![Encrypt-then-MAC (EtM)](/images/openvpn-full/EtM.png) | ![Encrypt-and-MAC (E-and-M)](/images/openvpn-full/EaM.png) | ![MAC-then-Encrypt (MtE)](/images/openvpn-full/MtE.png) | - -> https://en.wikipedia.org/wiki/Authenticated_encryption (Erişim Tarihi: 08.04.2023) - -- Birinci yaklaşım olan EtM'ye göre veri önce şifrelenir ardından başka bir anahtar ile özeti sonucu şifrelenir ve ortaya çıkan sonuç bloklar halinde birlikte gönderilir. Bunu kullanan gerçek dünya çözümlerine bakacak olursak IPSec protokolü ilk akla gelen olacaktır. Bu, AE'de en yüksek güvenlik tanımına ulaşabilen tek yöntemdir, ancak bu ancak kullanılan MAC algoritmasının bozulma içermediği veya henüz kırılmadığı takdirde elde edilebilir. SSHv2 için de çeşitli EtM şifre takımları mevcuttur. Ancak veri ve özet için anahtar ayrımının zorunlu olduğunu unutmayın (şifreleme ve anahtarlı karma için farklı anahtarlar kullanılmalıdır), aksi takdirde kullanılan belirli şifreleme yöntemine ve karma işlevine bağlı olarak potansiyel olarak güvensiz bir sonuç elde edebilirsiniz. - -- İkinci yaklaşım olan E&M'ye göre düz metin olan veri şifrelenir ve yanına düz metin verinin şifrelenmemiz halinin özeti eklenir. Burada sadece bir anahtar kullanılmış olmasına rağmen aynı veriye ait iki farklı sonucun (şifreleme sonucu ve özet sonucu) olması güvenliğin yeterince iyi olmadığını açıkca gözler önüne sermektedir. Bu sistemi kullanan gerçek dünya çözümü olarak SSH'ın ilk versiyonlarını örnek gösterebiliriz. Bunu geliştirmek için ayrıca gönderilen özet dosyasını da aynı anahtar ile şifreleme gibi yöntemler denenmiştir. - -- Üçüncü ve bildiğim son yaklaşım olan MtE'ye göre düz metine dayalı olarak bir özet dosyası üretilir. Ardından düz metin ve özet dosyası birlikteyken anahtar ile şifrelenir. Şifreli metin ve şifreli özet dosyası birlikte gönderilir. Bunu kullanan gerçek dünya çözümlerine bakacak olursak ilk ve en önemlisi SSL/TLS uygulamalarıdır. SSL/TLS uygulamalarının kendi içlerinde ne kadar güvenilir ve sürdürülebilir olduklarını hepimiz biliyoruz. Bunun ötesinde de güvenliği artırmak adına yıllar içersinde `MAC-then-pad-then-encrypt` gibi geliştirmeler yapıldı. Bu geliştirmeye göre önce düz metinin özeti alınır ardından blok boyutuna kadar doldurulur ve ardından şifreleme işlemi yapılır. Böylece daha da güvenilir bir şifreleme sonucu oluşur. Ama doldurma mekanizmasının belirli hatalar yapması durumunda Padding Oracle gibi saldırılara neden olduğu durumlar mevcuttur. - -![https://community.openvpn.net/openvpn/wiki/Gigabit_Networks_Linux (Erişim Tarihi: 08.04.2023)](/images/openvpn-full/TAP-TUN.png) - -Kullanılacak AEAD yaklaşımı da seçildikten sonra TAP veya TUN kullanımına göre yukarıdaki grafikte görülen yol izlenir. Bu yola göre kullanıcı alanında yapılan/yapılmak istenen eylem çekirdek (kernel) seviyesinde TAP/TUN adaptörlerine gider. Bu adaptörler çekirdek seviyesinde bulunmaları nedeniyle çok hızlı bir şekilde işlem yaparlar. Ardından sanal adaptörler ilgili kütüphane ile gerekli şifrelemeyi yapar, gerekirse özeti ekler ve paket boyutu ayarı yapar. Ardından sunucu Ethernet arayüzü üzerinden istemcinin Ethernet arayüzüne paketleri sırayla gönderir. Bunu alan istemci ise paketleri yeniden ayarlar, düzenler gerekirse birleştirir ve gerekli kütüphaneler ile şifresini çözer. Şifresini çözdükten sonra bunu sanal adaptör aracılığı ile istemcini son kullanıcısına iletir. Böylece tüm bu matematiksel işlemler, uğraşlar sonucunda birkaç çevrim neticesinde kullanıcı istediği içeriğe ulaşmış oldu. Anlatması oldukça uzun ama kullanması çok kolay sevgili okuyucular. Sadece GitHub sayfama girik ilgili [script sayfasını](https://github.com/wiseweb-works/openvpn-most-secure-install/) ziyaret etmeniz yeterlidir. İlgili script tüm bu ayarlamaları interaktif olarak sizin yerinize yapmaktadır. Size de arkanıza yaslanıp keyfini çıkarmak kalıyor. - -# SSS ve Son - -Bana [mail](mailto:wisewebworks@outlook.com) yoluyla, [Fosstodon](https://fosstodon.org/@wise) üzerinden veya [GitHub](https://github.com/wiseweb-works) üzerinden gelen soruları zaman zaman buraya eklemeye çalışacağım. Böylece tarihsel olarak da hangi tarihte ne gibi sorular olmuş veya çözümü mevcut mu gibi düşüncelere kapılmadan direk sonuca ulaşabileceksiniz. Bunun haricinde de teknik dökümanı değiştirmeden ekstra açıklama gerektiren sorular gelirse onları da bu kısma almayı düşünüyorum. +--- +title: "OpenVPN Derinlemesine Anlatım" +date: 2022-03-27 +tags: ["linux", "ssl", "security", "ecc", "elliptic curve", "openvpn", "tls", "aes"] +author: "Wise" +draft: false +--- +# Giriş ve Özet + +Bugün sizlerle kendi bence son zamanların en önemli yazılımlarından olan OpenVPN ile ilgili derinlemesine bir inceleme yapacağız. Bu incelememizde öncelikle OpenVPN'in ne için kullanıldığından bahsedeceğiz. Ardından programı çalıştırmak için nelere ihtiyaç duyduğumuzu ve ilk çalıştırma öncesi yapılması gerekenleri inceleyeceğiz. Son olarak da bağlantının başlatıldığı ilk andan verinin çözüldüğü son adıma kadar nelerin arka planda döndüğünü anlatmaya çalışacağım. Dolayısıyla yazımız tahminimce 3 bölüm ve gerekirse bir de soru-cevap bölümünden oluşacak. Şimdi kemerlerimizi bağlayalım ve internetin derin ve kasvetli dünyasında bir geziye çıkalım. + +## OpenVPN nedir ve ne için kullanılıyor ? + +Günümüzde artık internet üzerinden yapılmayan bir iş neredeyse kalmadı. Hatta normalde internet üzerinden olmayan çalışma eylemimiz bile pandemi ve yeni normal nedeniyle evden çalışmaya doğru evrildi. Fakat hem alışık olmadığımız bir çalışma yöntemi olması nedeniyle hem de insanlarımızın teknoloji ile arasının pek iyi olmaması nedeniyle büyük sorunlar yaşandı. İnsanların evlerindeki bilgisayarlardan ofisteki bilgisayarlarına bağlanması gerektiği anlaşılmadan önce bazı firmalar çalışanların evlerine ofis bilgisayarlarını gönderme gibi uçuk fikirler buldu. Bunun ne kadar hatalı bir gidiş yolu olduğunu kısa süre içinde aldıkları geri dönüşlerden çok iyi anladılar. Kısaca elektronik cihazların ofiste kalması ve bir şekilde uzaktan güvenli ve sürdürülebilir bir bağlantı yapılması gerektiği sonunda kabullenildi. Kurumlar daha önceleri de kendilerini böyle ihtiyaçlar içinde buluyordu elbette ama bu derece büyük ölçekli bir durum söz konusu değildi o zamanlar. Pandemi öncesinde PPTP, L2TP, IPSec, IKev2, SSTP ve nihayet OpenVPN gibi çeşitli protokoller kullanıyordu. Bunlar genelde belirli uzun ve havalı kelimelerin kısaltması olup temel mantıkları iki veya daha fazla cihazı birbirine bağlamak ve aynı ağdaymış gibi hareket etmelerini sağlamak üzerinedir. OpenVPN'den önceki protokoller belirli zayıflıkları, yavaşlıkları ve uygulanmasıyla ilgili teknik zorlukları da beraberlerinde getirdikleri için çok bahsetmeyeceğim. OpenVPN sunucu ve istemci rolündeki en az 2 cihazın birbirlerine bağlanması ve bunu endüstiri standartlarını karşılayacak şekilde yapmasına yarayan protokol ve programın adıdır. Ben uzak masaüstü programı kullanıyorum buna ne gerek var dediğinizi duyar gibiyim. Maalesef o ve onun gibi diğer tüm programlar temelde bu protokolü kullanmak durumunda kalıyorlar. En meşhurlarından olan TeamViewer programında kalkan simgesine veya bağlantı ayrıntılarına bastığınız takdirde OpenVPN protokolünü görebilirsiniz. + +## OpenVPN bağlantısı kurmak için nelere ihtiyaç duyarız ? + +Öncelikle hem sunucu hem de istemci (bağlanacak cihaz) tarafında OpenVPN'in kurulu olması gerekiyor. Ardından cihazların hangi şartlar altında iletişim kuracaklarını gösterir bir ayar (config) dosyasının düzenlenmesi gerekmektedir. Asıl olay zaten bu config dosyasının üretilmesi ve istemci tarafından kullanılmasıdır. Bu config dosyası sunucu tarafından kullanılan server_config ve istemci tarafından kullanılan client_config olarak ikiye ayrılır. + +### Server tarafında tutulan ayar dosyası şu girdileri içermektedir + +- `port 1194` OpenVPN bağlantısını yapmak için kendisine hangi port üzerinden bağlantı talebi geleceğini belirtir. +- `proto tcp` Bağlantının TCP veya UDP üzerinden yapılması mümkün. Seçim için girilen ayar girdisi. +- `dev tun` TAP veya TUN arabirimi kullanılabilir. Bunlar sanal arabirimlerdir. TAP layer 2 bir bağlantı kurarken TUN layer 3 bir bağlantı kurar. +- `user nobody` Bağlanan kullanıcıların sunucu üzerinde yetkisiz bir kullanıcıya linklenmesini sağlıyor. +- `group $NOGROUP` Bağlanan kullanıcıların sunucu üzerinde grup olarak da yetkisiz bir gruba linklenmesini sağlıyor. +- `persist-key` Sanal arabirimin oluşturulması ve yeniden başlatılması ile ilgili bir yetkilendirme ayarı +- `persist-tun` Yine aynı şekilde sanal arabirimin oluşturulması ve yeniden başlatılması ile ilgili bir yetkilendirme ayarı +- `keepalive 10 120` Kaç adet bağlantının aktif tutulacağını ve ne kadar süre iletişim kurulmaz ise aktif bağlantının sonlandırılacağı ile ilgili bir ayar +- `ifconfig-pool-persist ipp.txt` OpenVPN tarafından istemcilere sanal ağda verilen IP adreslerinin tutulması ve tekrar bağlandıkları takdirde aynı adreslerin verilmesi için bir ayar +- `push "dhcp-option DNS 1.1.1.1"` Sunucunun ağa çıkarken kullanması için bir DNS ayarı +- `compress` Sıkıştırma seçeneklerinin ayarlandığı kısım +- `dh none` Diffie-Hellman'ın açılıp kapatılması ile ilgili bir ayar +- `ecdh-curve` Eğer Elliptik Eğri Diffie-Hellman kullanıyor iseniz yanında seçmeniz gereken eğrinin ayarlandığı ayar +- `dh dh.pem` Diffie-Hellman kullanıyor iseniz önceden oluşturmanız gereken PEM dosyasının konumunu belirten ayar +- `tls-crypt tls-crypt.key` TLS katmanının pre-shared master öncesinde dahi şifrelenmesi için gerekli ayar +- `tls-auth tls-auth.key 0` TLS katmanının pre-handshake aşamasında şifrelenmesinin de ötesinde tarafların da doğrulanmasını sağlayan ayar +- `crl-verify crl.pem` Üretilen sertifikaların revoke edilip edilmediğinin CRL listesi üzerinden kontrol edilmesine yarayan ayar +- `ca ca.crt` Üretilen sertifikaya ait sertifika otoritesinin sertifikasının konumunu bildiren bir ayar +- `cert $SERVER_NAME.crt` Sunucunun sertifikasının konumunu bildiren bir ayar +- `key $SERVER_NAME.key` Sunucunun sertifikasının yanında yine gerekli olan asimetrik secret keyinin konumunu bildiren bir ayar +- `auth $HMAC_ALG` Veri kanalı ve gerekirse `tls-auth` için hangi özet algoritmasının kullanılacağını bildiren bir ayar +- `cipher $CIPHER` Veri kanalı için hangi şifreleme algoritmasının kullanılacağını bildiren bir ayar +- `ncp-ciphers $CIPHER` Sunucunun kullanabileceği şifreleme algoritmalarını bildiren bir ayar +- `tls-server` Sunucunun TLS kanalını kullanmasını söyleyen bir ayar +- `tls-version-min 1.2` TLS kanalında kullanılması için en düşük versiyonu bildiren bir ayar +- `tls-cipher $CC_CIPHER` Veri kanalından hariç TLS katmanında da şifreleme kullanılıyor bu da kontrol kanalı şifrelemesini bildiren ayar +- `client-config-dir /etc/openvpn/ccd` İstemci ayar dosyalarının tutulduğu konumu bildiren ayar +- `status /var/log/openvpn/status.log` Durum raporlarının yazılacağı konumu ve log dosyalarının tutulduğu konumu bildiren ayar +- `verb 3` Verbose kelimesinin kısaltılmışı olan bu ayar ne kadar detaylı durum raporu verileceğinin ayarıdır. + +### İstemci tarafında tutulan ayar dosyası şu girdileri içermektedir + +- `client` İlgili cihazın istemci rolünde olduğunu belirtiyor +- `proto tcp-client` Protokol olarak TCP'nin kullanılacağını bildiriyor +- `remote $IP $PORT` Bağlanılacak sunucu(ların) IP adresinin ve Port numarasının ayarladığı kısım +- `dev tun` TUN/TAP arabirimlerinden hangisinin kullanılacağını ayarlıyor +- `resolv-retry infinite` Eğer IP veya DNS nedeniyle adres çözümlemesi gecikir ise ne kadar süre ile bekleyeceğini söylüyoruz +- `nobind` Lokaldeki herhangi bir adrese bağlanılmamasını bildiren ayar +- `persist-key` Yeniden başlatma durumunda anahtar dosyalarının ek bir yetkiye gerek kalmadan okunabilmesini yarar +- `persist-tun` Aynı şekilde yeniden başlatma durumunda TUN/TAP arabiriminin yetkiye gerek kalmadan uyandırılabilmesine yarar +- `remote-cert-tls server` Bağlanılan sunucunun sertifikasını TLS katmanında doğrulanmasını sağlar +- `verify-x509-name $SERVER_NAME name` Sunucunun geri döneceği sertifikasındaki ismi ve sunucunun isminin ne olması gerektiğini bildiren komut +- `auth $HMAC_ALG` Doğrulama için hangi algoritmanın kullanılacağını bildiren komut +- `auth-nocache` Oturum açmak için gerekli parolayı önbelleğe almaz +- `cipher $CIPHER` Şifreleme için kullanılacak algoritmayı seçmeye yarayan komut +- `tls-client` TLS iletişimi sırasında TLS'yi etkinleştirir ve istemci rolünü üstlenir +- `tls-version-min 1.2` En düşük TLS versiyonunu ayarlar +- `tls-cipher $CC_CIPHER` TLS kontrol kanalında kullanılacak şifreleme algoritmasını seçer +- `ignore-unknown-option block-outside-dns` Bilinmeyen DNS adreslerinin kullanılmasını engeller +- `setenv opt block-outside-dns` Windows 10 için DNS sızıntılarını engeller +- `verb 3` Rapor verme derecesini belirler +- `compress` Sıkıştırma algoritması ayarları burada bildirilir +- `"/etc/openvpn/easy-rsa/pki/ca.crt"` Beklenilen sunucu sertifika otoritesi dosyasının Hard-Coded gömülmesi +- `"/etc/openvpn/easy-rsa/pki/issued/$CLIENT.crt"` İstemci sertifika dosyasının Hard-Coded gömülmesi +- `"/etc/openvpn/easy-rsa/pki/private/$CLIENT.key"` İstemci asimetrik secret keyinin Hard-Coded gömülmesi +- `"/etc/openvpn/tls-crypt.key"` TLS crypt için key dosyasının belirtilmesi +- `"/etc/openvpn/tls-auth.key"` TLS auth için key dosyasının belirtilmesi +- `key-direction 1` TLS katmanı şifrelenmesi için istemci ve sunucuya rol atıyor (0 ve 1 şeklinde) + +Bu ayarları ve daha bir çoğunun ayrıntılı dökümantasyonunu [OpenVPN](https://openvpn.net/community-resources/reference-manual-for-openvpn-2-4/) web sayfasında bulabilirsiniz. + +## OpenVPN bağlantısı kurulurken neler oluyor ? + +OpenVPN ile bağlantı kurduğum her zaman kendimi Yıldız Filosu planlarını kaçıran R2-D2 gibi hissediyorum. İnsanlar kendilerini her zaman için derinlemesine bir inceleme içerisinde bulmak istemiyorlar ve birilerinin onlara neyin nasıl döndüğünü açıklamalarını isteyebiliyorlar. Benim bu yazıyı kaleme alma amacımda aslında bu soruyu kendime sormuş olmam ve cevabını almak için çok çaba sarfetmiş olmam. Sizin de bu kadar uğraşmanızı istemem fakat size hemencecik bunu yükle gerisini düşünme o iş bende de diyemem. Başta söz verdiğim gibi derinlemesine bir şekilde bu süreci sizlere anlatacağım ve kararı size bırakacağım. Bir OpenVPN bağlantısında artısıyla eksisiyle (benim şu ana kadar çözebildiğim şekliyle) süreç şöyle işliyor. Önce bir TCP/UDP bağlantısı kuruyorsunuz. TCP kullanan her uygulama gibi bir süreç yürütüyorsunuz ve ardından TLS katmanına geçiyorsunuz. TLS katmanında el sıkışma (handshake) ve bazı kimlik doğrulama işlemleri yapıyorsunuz. Bu katmana aynı zamanda kontrol kanalı da deniliyor. Ardından belirli bir iletişim tutturulmuş oluyor ve veri kanalına geçiliyor. Veri veya data kanalında bu sefer gönderilecek veri paketlerinin şifrelenmesi ve çözülmesi süreci başlıyor. Bunun için yine cihazlar birbirleri ile konuşuyor ve belirli ortak şartlar altında veriler gönderilmeye başlanıyor. Kısaca bu şekilde anlattığım sürecin sonunda 0'dan başlattığımız iletişim bize güvenli ve istediğimiz şekilde verilerin ulaşması ile son buluyor veya açık tutulan bağlantı üzerinden bu sefer tersine bir yolla yeniden istekler iletiliyor. Böylece iç içe borular gibi bir sistem ortaya çıkıyor. Yazı için gerekli olan tek önemli şeyi buraya yazmak gerekirse eğer: + +- `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P512` şeklinde olacaktır. + - Burada `TLS` girdisi kontrol kanalının TLS katmanı üzerinden yürütüleceğini belirtir. Diğer alternatifler `SSL` veya `NULL`'dur. + - `ECDHE` girdisi Elliptik Diffie-Hellman algoritması kullanılarak ilk ön-anahtarın üretileceğini belirtir. Diğer alternatifler `DHE`, `DH` veya kullanmamaktır. + - `ECDSA` verisi karşılıklı kimlik doğrulama ve asimetrik anahtar için Elliptik Dijital İmza Sertifikası Algoritmasının kullanılacağını belirtir. Diğer kullanılabilir alternatif `RSA`'dır. Diğerlerini saymaya gerek bile yok. + - `AES_256_GCM` veri kanalında kullanılacak şifreleme algoritmasının belirtir. Diğer alternatifler `AES-128-CBC`, `AES-128-GCM` ve `AES-256-CBC`'dir + - `SHA384` kullanılacak özet algoritmasını belirtir. Diğer alternatif `SHA256`'dır. + - `P512` ise kullanılacak elliptik eğrinin Prime-512 adlı eğri olarak seçilmesini sağlar. Diğer alternatifler `P-256` ve `P-384`'dür. + +### TCP bağlantısının kurulması süreci + +Şimdi kafanızda sürecin yaklaşık bir resmi oluştu ise başlangıcı TCP sürecinin anlatımıyla yapıyorum. Olayımızda bir istemci ve bir sunucunun olduğunu ve bağlantının sadece bu ikisinden ibaret olduğunu düşünelim. İstemci bağlanmak istediği sunucuya bir SYN (m) paketi gönderir. Sunucu ise buna cevap olarak aynı port üzerinden bir SYN (n) paketi ve ACK (m+1) paket gönderir. Bunu alan istemci de cevap olarak ACK (n+1) şeklinde dönüş yapar ve 3'lü TCP el sıkışması veya 3 Way TCP handshake gerçekleşmiş olur. Böylece belirtilen port üzerinden istemci ve sunucu arasında açık bir kanalımız oluştu. + +![https://blog.shiftasia.com/what-happen-when-access-website (Erişim Tarihi: 08.04.2023)](/images/openvpn-full/TCP-Handshake.jpg) + +--- +![https://www.netscout.com/blog/asert/ddos-attacks-ssl-something-old-something-new (Erişim Tarihi: 08.04.2023)](/images/openvpn-full/TCP-Handshake-2.png) + +Fotoğraflarda da görüleceği üzere eğer süreç sorunsuz işler ise 3 adımda iletişim kurulabiliyor. Fakat neden 3 adımda bu işi yapıyoruz daha kısa şekilde olmaz mı derseniz size (şimdilik) hayır olmaz full-duplex bir iletişim için her iki tarafın da SYN ve ACK paketlerini göndermesi gerekiyor derim. İleride belki farklı yollarını da anlatırım ama şimdilik böyle. Zaten işin TCP/UDP kısmı her zaman için kısa ve basittir. + +### TLS katmanındaki işletilen süreç + +TCP üzerinden bir iletişim kurulmasının ardından yine muhabbeti başka bir aşamaya taşıyan kişi istemci oluyor. Her zaman için istemciler sunucudan bir şeyler talep eder veya bir cevap ister. Sunucular genel olarak kendilerine gelmeyen bir isteği cevapladığı çok görülmemiştir. Önce talep sonra arz ilkesine göre süreç ilerler. Evet, taraflar TLS katmanındalar şimdi. İstemci sunucuya önce bir merhaba diyor. Şaka değil gerçek. İstemci tarafından gönderilen ilk pakete `Client-Hello` paketi denir. Bu paketin yanında (süreci hızlandırmak adına) desteklediği şifreleme algoritmalarını belirten `Supported-Chipers` paketi, istemci tarafından rastgele üretilmiş bir sayı, aynı IP adresinde birden fazla hizmet çalıştırılıyor ise bir `SNI` sunucu adı indikatörü ve yine gerekiyor ise oturum ID'si gönderilir. Sunucunun buna cevabı ise öncelikle kibar bir merhaba demek oluyor. Çünkü sunucunun cevaben gönderdiği ilk pakete de `Server-Hello` paketi denir. Bu paketin yanında sunucu sertifikasını, kendi desteklediği şifreleme algoritmalarını ve seçtiği algoritmayı belirten `Selected-Chiper` paketi, kendisinin ürettiği rastgele bir sayıyı, gerekirse Oturum ID'sini ve aynı IP üzerinden birden fazla istemci bağlanıyor ise buna ilişkin SNI benzeri bir ID'yi gönderir. İstemci öncelikle iletişime başladığı tarafından gerçekten beklediği kişi olup olmadığını sunucu sertifikası ile doğrular. Ayrıca bazı durumlarda da sunucu istemcinin beklediği istemcilerden biri olup olmadığını yine sertifika ile doğrular. Eğer bu karşılıklı doğrulama (mutual-authentication) süreci olumlu sonuçlanır ise bir sonraki aşamaya geçilir. Anahtar üretim ve değişim süreci tetiklenmiş olur. Bu aşamda yine istemci devreye girer ve güvensiz önkabul edilen bu iletişim sırasında belirledikleri algoritma ile anahtar değiştirmek istediğini söyler. Taraflar Diffie-Hellman veya ECDHE ile bir önanahtar oluşturmaya başlarlar. Bunun için istemci ve sunucu tarafından ön-sırlar paylaşılır. Bir takım matematiksel işlemler yapılarak bulunan cevaplar karşıya gönderilir ve tekrar matematiksel işlemler yapılarak aynı sonuca ulaşılır. İşte ulaşılan sonuç aralarında güvenli bir şekilde oluşturdukları ilk ön-anahtar oluyor. Bundan sonra belirledikleri şifreleme algoritması ile +iletişime geçmek için kontrol kanalından hariç bir veri kanalı oluşturulur ve süreç oradan devam eder. + +![https://www.researchgate.net/publication/298065605_A_multi-level_framework_to_identify_HTTPS_services (Erişim Tarihi: 08.04.2023)](/images/openvpn-full/TLS-Handshake.png) + +--- +![](/images/openvpn-full/TLS-Handshake-2.png) + +Fotoğraflarda da görülebileceği üzere süreç bir web sayfasına bağlanılırken yaşanan süreçle neredeyse aynı. Sadece ihtiyaçlara göre belirli aşamalar ekleniyor, çıkarılıyor veya değiştiriliyor. Örneğin İleri Seviye Gizlilik anlamına gelen PFS gereğince taraflar ön-anahtarı sunucunun asimetrik anahtarı ile iletmiyor. Çünkü bu durumda her oturum için aynı anahtar kullanılacağı için verilerin depolanıp daha sonra anahtar açığa çıktığı bir gün beklenerek veriler geçmişe dönük okunabilir bir hale gelecektir. Bu yüzden bu değişiklik yapıldı. Yine sıfır güven tehdit modeli gereğince her bir katmanın ve sürecin bir diğerinin işini doğru yapacağına güvenmeden süreci ilerletmesini istiyorum. Bu yüzden TLS katmanındaki o ilk iletişim anında dahi paketlerin `tls-auth` özelliği gereğince şifrelenmesini ve gelen-giden verilerin bütünlüğünün doğrulanmasını istiyoruz. Daha ilk merhaba dediğiniz andan itibaren üçüncü kişiler sizin ne konuştuğunuzu hangi aşamada olduğunuzu anlayamayacaklardır. Bunun için önceden belirlenmiş bir anahtar/anahtarlar ile ilk iletişim başlatılır ve gerekirse belirli aralıklarla bu anahtarlar yenilenir. Böylece TLS katmanında ilk ön-anahtar oluşturulana kadar dahi gizlilikten ödün verilmemiş ve yetkisiz kişilerce boşuna tarafik yaratılmamış olur. + +### Veri katmanında işleyen süreç + +Eğer tüm bu süreç başarılı bir şekilde tamamlanmış ve veri kanalına geçilebildiyse eğer artık işin en güzel kısmına gelmiş bulunuyorsunuz. Veriler AES şifreleme methodu ile şifrelenecek. Şifreleme sırasında seçiminize göre CBC-GCM counter moduna göre tablolar karıştırılacak ve bu süreçte seçiminize göre 128 veya 256 bit uzunluğunda şifreleme anahtarı kullanılacak. Tabi ne hangisini seçerseniz seçin şifreleme blok uzunluğu 128 bit olucak. Değişen sadece şifreleme anahtarı uzunluğu. Benim bu anlatımım için seçmiş olduğum AES-256-GCM bir AEAD şifreleme türüdür. Diğer kanallardan ve süreçlerden bağımsız olarak gönderdiği verileri belirli bir aşamada özetini çıkartır ve özeti ile birlikte gönderir. Böylece 'Authentication Encryption with associated data' anlamına gelen AEAD'de doğrulama ve şifreleme işlevleri yerine getirilmiş oluyor. Burada bir ayrıma gidilmesini gerektirecek şöyle bir sorun mevcuttur. Şifreleme ve Özet alma algoritmalarını hangi aşamada ve sırayla kullanacağız. + +|||| +|:---:|:---:|:---:| +| ![Encrypt-then-MAC (EtM)](/images/openvpn-full/EtM.png) | ![Encrypt-and-MAC (E-and-M)](/images/openvpn-full/EaM.png) | ![MAC-then-Encrypt (MtE)](/images/openvpn-full/MtE.png) | + +> https://en.wikipedia.org/wiki/Authenticated_encryption (Erişim Tarihi: 08.04.2023) + +- Birinci yaklaşım olan EtM'ye göre veri önce şifrelenir ardından başka bir anahtar ile özeti sonucu şifrelenir ve ortaya çıkan sonuç bloklar halinde birlikte gönderilir. Bunu kullanan gerçek dünya çözümlerine bakacak olursak IPSec protokolü ilk akla gelen olacaktır. Bu, AE'de en yüksek güvenlik tanımına ulaşabilen tek yöntemdir, ancak bu ancak kullanılan MAC algoritmasının bozulma içermediği veya henüz kırılmadığı takdirde elde edilebilir. SSHv2 için de çeşitli EtM şifre takımları mevcuttur. Ancak veri ve özet için anahtar ayrımının zorunlu olduğunu unutmayın (şifreleme ve anahtarlı karma için farklı anahtarlar kullanılmalıdır), aksi takdirde kullanılan belirli şifreleme yöntemine ve karma işlevine bağlı olarak potansiyel olarak güvensiz bir sonuç elde edebilirsiniz. + +- İkinci yaklaşım olan E&M'ye göre düz metin olan veri şifrelenir ve yanına düz metin verinin şifrelenmemiz halinin özeti eklenir. Burada sadece bir anahtar kullanılmış olmasına rağmen aynı veriye ait iki farklı sonucun (şifreleme sonucu ve özet sonucu) olması güvenliğin yeterince iyi olmadığını açıkca gözler önüne sermektedir. Bu sistemi kullanan gerçek dünya çözümü olarak SSH'ın ilk versiyonlarını örnek gösterebiliriz. Bunu geliştirmek için ayrıca gönderilen özet dosyasını da aynı anahtar ile şifreleme gibi yöntemler denenmiştir. + +- Üçüncü ve bildiğim son yaklaşım olan MtE'ye göre düz metine dayalı olarak bir özet dosyası üretilir. Ardından düz metin ve özet dosyası birlikteyken anahtar ile şifrelenir. Şifreli metin ve şifreli özet dosyası birlikte gönderilir. Bunu kullanan gerçek dünya çözümlerine bakacak olursak ilk ve en önemlisi SSL/TLS uygulamalarıdır. SSL/TLS uygulamalarının kendi içlerinde ne kadar güvenilir ve sürdürülebilir olduklarını hepimiz biliyoruz. Bunun ötesinde de güvenliği artırmak adına yıllar içersinde `MAC-then-pad-then-encrypt` gibi geliştirmeler yapıldı. Bu geliştirmeye göre önce düz metinin özeti alınır ardından blok boyutuna kadar doldurulur ve ardından şifreleme işlemi yapılır. Böylece daha da güvenilir bir şifreleme sonucu oluşur. Ama doldurma mekanizmasının belirli hatalar yapması durumunda Padding Oracle gibi saldırılara neden olduğu durumlar mevcuttur. + +![https://community.openvpn.net/openvpn/wiki/Gigabit_Networks_Linux (Erişim Tarihi: 08.04.2023)](/images/openvpn-full/TAP-TUN.png) + +Kullanılacak AEAD yaklaşımı da seçildikten sonra TAP veya TUN kullanımına göre yukarıdaki grafikte görülen yol izlenir. Bu yola göre kullanıcı alanında yapılan/yapılmak istenen eylem çekirdek (kernel) seviyesinde TAP/TUN adaptörlerine gider. Bu adaptörler çekirdek seviyesinde bulunmaları nedeniyle çok hızlı bir şekilde işlem yaparlar. Ardından sanal adaptörler ilgili kütüphane ile gerekli şifrelemeyi yapar, gerekirse özeti ekler ve paket boyutu ayarı yapar. Ardından sunucu Ethernet arayüzü üzerinden istemcinin Ethernet arayüzüne paketleri sırayla gönderir. Bunu alan istemci ise paketleri yeniden ayarlar, düzenler gerekirse birleştirir ve gerekli kütüphaneler ile şifresini çözer. Şifresini çözdükten sonra bunu sanal adaptör aracılığı ile istemcini son kullanıcısına iletir. Böylece tüm bu matematiksel işlemler, uğraşlar sonucunda birkaç çevrim neticesinde kullanıcı istediği içeriğe ulaşmış oldu. Anlatması oldukça uzun ama kullanması çok kolay sevgili okuyucular. Sadece GitHub sayfama girik ilgili [script sayfasını](https://github.com/wiseweb-works/openvpn-most-secure-install/) ziyaret etmeniz yeterlidir. İlgili script tüm bu ayarlamaları interaktif olarak sizin yerinize yapmaktadır. Size de arkanıza yaslanıp keyfini çıkarmak kalıyor. + +# SSS ve Son + +Bana [mail](mailto:wisewebworks@outlook.com) yoluyla, [Fosstodon](https://fosstodon.org/@wise) üzerinden veya [GitHub](https://github.com/wiseweb-works) üzerinden gelen soruları zaman zaman buraya eklemeye çalışacağım. Böylece tarihsel olarak da hangi tarihte ne gibi sorular olmuş veya çözümü mevcut mu gibi düşüncelere kapılmadan direk sonuca ulaşabileceksiniz. Bunun haricinde de teknik dökümanı değiştirmeden ekstra açıklama gerektiren sorular gelirse onları da bu kısma almayı düşünüyorum. diff --git a/content/post/pgp-ve-gizlilik.md b/content/post/pgp-ve-gizlilik.md index 7e36419f..aa1f002d 100644 --- a/content/post/pgp-ve-gizlilik.md +++ b/content/post/pgp-ve-gizlilik.md @@ -1,26 +1,26 @@ ---- -title: "PGP nedir ve gerçekten de oldukça iyi bir gizlilik sağlıyor mu?" -date: 2020-05-10 -tags: ["pgp", "gizlilik", "security"] -author: "Wise" -draft: false ---- -{{< youtube VGz1dZ4Sg-g >}} - -PGP Türkçede oldukça iyi gizlilik anlamına gelen Pretty Good Privacy kelimesinin baş harflerinde oluşturulmuş bir veri şifreleme, şifre çözme ve verileri elektronik olarak imzalama programıdır. [Phil Zimmermann](https://tr.wikipedia.org/w/index.php?title=Phil_Zimmermann&action=edit&redlink=1) tarafından 90'lı yılların başında akademik bir makale olarak ortaya çıkmış ve yayımlandığı dönemden çok sonra gerçekten kullanılmaya ve getirilerinden yararlanılmaya başlanmıştır. Söz konusu program ilk ortaya çıktığı zamanlarda bir ihtiyacın kendisini ortaya çıkmaya zorlamasından ziyade daha çok bir düşünce deneyi olarak iletişimin her iki tarafı arasındaki verilerin şifrelenebileceği ve bunun nasıl yapılması gerektiği sorusu üzerine ortaya çıkmıştır. Ortaya çıkışının ardından gönderilen verilen şifrelenmesinin ve şifresinin taraflarca çözülmesinin yanına bir de verinin bütünlüğünün korunmasını sağlayan özet fonksiyonu ve mesajı gönderen kişinin kimliğinin doğrulanması sağlayan (ve kimi zaman inkar edilemezlik olarak da anılan) imzalama özelliği eklenmiştir. Ortaya çıktığı dönemde ve sonrasında açık kaynak kodlu olarak yayımlanmaya devam etmiş ve günümüzde OpenPGP adı altında gelişerek faaliyetlerine devam etmektedir. PGP’nin ortaya çıktığı 1991 yılından 6 sene sonra yani 1997 yılında kendilerine Internet Engineering Task Force (görev gücü biraz abartı olmadı :D) adını veren bir çalışma grubu PGP programının sağlamış olduğu şifreleme özelliklerinin piyasa standartı haline gelmesi ve kullanımının kolaylaştırılması için yazılar yayımlamaya başladılar. - -![https://zappysys.com/blog/ssis-pgp-encryption-decryption (Erişim Zamanı: 08.04.2023)](/images/pgp-anlatim/pgp-encryption.png) - -PGP’nin şifreleme ve şifre çözme özelliklerinin nasıl çalıştığını ve internet alemi için neden bu kadar büyük bir atılım anlamına geldiğini insanlara anlatmaya başladılar. PGP asimetrik şifreleme denilen ve günümüzde internet tarayıcılarından elektronik imza ile girişi destekleyen tüm internet sitelerinde ve özellikle bankalarda kullanılan bir şifreleme/şifre çözme şeklidir. Asimetrik şifrelemeden kısaca bahsedersek eğer (sadece asimetrik şifrelemeyi tüm detaylarıyla anlatan bir yazı da gelecek) şifrelemeyi yapan anahtar ile şifrelenmiş veriyi açacak olan anahtarın farklı olduğu ve birbirlerinden üretildiği bir şifreleme türüdür. Bu şifreleme türünde sizin public (genel) anahtarınız ve private (gizli) anahtarınız mevcuttur. Bu anahtarlardan birisi ile yapılan şifrelemeyi aynı anahtar açamayıp sadece diğer anahtar ile açılması/çözülmesi mümkündür. Daha kolay anlaşılması için bir örnek üzerinden gidelim. Eskiden çelik kapılarda ve kepenklerde bolca kullanılan asma kilitleri gözümüzün önüne getirelim. Şimdi bu kilitler üretildiği zaman bu kilidi açabilecek anahtar da yanında üretilip son kullanıcıya yanında veriliyor. Bana şifreli bir şekilde bir yazı veya bir dosya göndermek istediğinizi düşünelim. Görece olarak güvenli bulduğunuz bir kutuya bana göndermek istediğiniz dosyaları koyup daha sonra da benden almış olduğunuz şahsi asma kilidimi üzerine takıyorsunuz. Bu aşamada benim size vermiş olduğum tek şey bir asma kilit ve anahtarlar hala bende. Kutu kapatıldıktan ve asma kilit üzerine takıldıktan sonra asma kilidin demirlerini ittirerek içine geçirip kutuyu tamamen kilitli bir hale getiriyorsunuz. Bu aşamadan sonra size vermiş olduğum asma kilidi kullanarak kutuyu açma imkanınız yok hatta içine koyduğunuz şeyleri de artık kapattıktan sonra tekrar değiştirmeniz mümkün değil. Benim aynı asma kilitten yüzlercesine sahip olduğumu ve hepsinin aynı ve sadece bende olan bir anahtar ile açıldığını düşündüğünüzde etrafımdaki insanlara anahtarsız bir asma kilit vermenin çok da sorun olmayacağından emin olabilirsiniz. Asimetrik anahtar ile şifreleme yapılırken de gizli (private) anahtarınız ile yüzlerce genel (public) anahtar üretebilirsiniz fakat private keyiniz her zaman için tekdir. Artık benim kilidim ile kilitlenmiş kutuyu bana göndermeniz ve benim de onu kendime ait gizli anahtar ile açmam sonucunda güvenli bir şekilde bir iletişim sağlamış olduk. - -PGP’nin bize sağlamış olduğu bir anahtar ile şifreleyip sadece diğer anahtar ile o verinin açılabilmesi özelliği dönemi için çok üst düzey bir şifreleme ve güvenlik işleviydi. Şifreleme için kullanılan anahtarların uzunluğu 2048 Bit, 3072 Bit ve 4096 Bit boyutundaydı. 1 Bitin 8 Bayt olduğunu düşünürseniz bu sayıların hem bir insan için hem de o dönemin bilgisayarları için oldukça büyük sayılar olduğunu anlamışsınızdır. O dönem daha hızlı olması (düşündüğünüz kadar hızlı değil) için en düşük anahtar boyutu olan 2048 Bit kullanılmış olup genel olarak gönderilen maillerin içeriğinin (sadece içerik kısmı) ve ekte gönderilen dosyaların şifrelenmesi şeklinde kullanılmıştır. 2048 Bit yerine en yüksek anahtar boyutu olan 4096 Bit kullanıldığı zaman her ne kadar anahtar boyutu 2 kat artmış olsa da hız yerine göre 4 ile 10 kat arasında azalmaktaydı. Ortalama 200–400 karakterden oluşan bir salt yazının şifrelenmesi sırasında en düşük anahtar boyutu ile şifrelenmesi bilgisayarınızın gücüne bağlı olarak 1 ila 10 sn arasında değişebiliyordu. Bu nedenle daha uzun anahtar boyutuna sahip 4069 Bit’in şifreleme süreci çok uzun sürmekteydi. Şimdi bakıldığında 1–2 dk gibi süreler çok kısa gibi gelse de sadece bir metni göndermek için bu kadar beklemenizin gerekiyor olması o dönem için gerçekten can sıkıcıydı. Üstelik sizin şifreleme sürecinde beklediğiniz kadar da şifrelemeyi çözecek anahtara sahip kişiyi de çözüm sırasında bekletiyordunuz. - -PGP ile veri gönderilmesi ile ilgili bir örnek ile devam edelim. Mesela sizin için çok önemli olan bir veriyi göndermek istiyorsunuz. Önce farazi olarak (umarım nükleer fırlatma kodları değildir) bir yazılı metin seçelim. Benim seçtiğim veri: - -> “u, iki u daha, birincisi küçük u, ikincisi büyük u, 1 j, 3 3 3( üç tane 3 rakamı ama üçüncüsü küçük 3), yumuşak g, 6 a, k, küçük hığıı, 6 milyon. iki milyar. ama iki milyar yazıyla” ALINTI - -Önce bu veriyi… arkadaşlar yazıyı yazarken sıkıldım. Kusura bakmayın bunu da bu kadar anlatmış olayım. Ben keyfime düşkün bir adamım sıkılınca yapamıyorum. - -{{< youtube Z8aqzdARZns >}} - -NOT: Bu yazı daha önce şahsi medium.com adresimde yayımlanmıştır. Kişisel portfolyo oluşturmak adına şahsi sitemde yeniden yayımlama ihtiyacı hissettim. +--- +title: "PGP nedir ve gerçekten de oldukça iyi bir gizlilik sağlıyor mu?" +date: 2020-05-10 +tags: ["pgp", "gizlilik", "security"] +author: "Wise" +draft: false +--- +{{< youtube VGz1dZ4Sg-g >}} + +PGP Türkçede oldukça iyi gizlilik anlamına gelen Pretty Good Privacy kelimesinin baş harflerinde oluşturulmuş bir veri şifreleme, şifre çözme ve verileri elektronik olarak imzalama programıdır. [Phil Zimmermann](https://tr.wikipedia.org/w/index.php?title=Phil_Zimmermann&action=edit&redlink=1) tarafından 90'lı yılların başında akademik bir makale olarak ortaya çıkmış ve yayımlandığı dönemden çok sonra gerçekten kullanılmaya ve getirilerinden yararlanılmaya başlanmıştır. Söz konusu program ilk ortaya çıktığı zamanlarda bir ihtiyacın kendisini ortaya çıkmaya zorlamasından ziyade daha çok bir düşünce deneyi olarak iletişimin her iki tarafı arasındaki verilerin şifrelenebileceği ve bunun nasıl yapılması gerektiği sorusu üzerine ortaya çıkmıştır. Ortaya çıkışının ardından gönderilen verilen şifrelenmesinin ve şifresinin taraflarca çözülmesinin yanına bir de verinin bütünlüğünün korunmasını sağlayan özet fonksiyonu ve mesajı gönderen kişinin kimliğinin doğrulanması sağlayan (ve kimi zaman inkar edilemezlik olarak da anılan) imzalama özelliği eklenmiştir. Ortaya çıktığı dönemde ve sonrasında açık kaynak kodlu olarak yayımlanmaya devam etmiş ve günümüzde OpenPGP adı altında gelişerek faaliyetlerine devam etmektedir. PGP’nin ortaya çıktığı 1991 yılından 6 sene sonra yani 1997 yılında kendilerine Internet Engineering Task Force (görev gücü biraz abartı olmadı :D) adını veren bir çalışma grubu PGP programının sağlamış olduğu şifreleme özelliklerinin piyasa standartı haline gelmesi ve kullanımının kolaylaştırılması için yazılar yayımlamaya başladılar. + +![https://zappysys.com/blog/ssis-pgp-encryption-decryption (Erişim Zamanı: 08.04.2023)](/images/pgp-anlatim/pgp-encryption.png) + +PGP’nin şifreleme ve şifre çözme özelliklerinin nasıl çalıştığını ve internet alemi için neden bu kadar büyük bir atılım anlamına geldiğini insanlara anlatmaya başladılar. PGP asimetrik şifreleme denilen ve günümüzde internet tarayıcılarından elektronik imza ile girişi destekleyen tüm internet sitelerinde ve özellikle bankalarda kullanılan bir şifreleme/şifre çözme şeklidir. Asimetrik şifrelemeden kısaca bahsedersek eğer (sadece asimetrik şifrelemeyi tüm detaylarıyla anlatan bir yazı da gelecek) şifrelemeyi yapan anahtar ile şifrelenmiş veriyi açacak olan anahtarın farklı olduğu ve birbirlerinden üretildiği bir şifreleme türüdür. Bu şifreleme türünde sizin public (genel) anahtarınız ve private (gizli) anahtarınız mevcuttur. Bu anahtarlardan birisi ile yapılan şifrelemeyi aynı anahtar açamayıp sadece diğer anahtar ile açılması/çözülmesi mümkündür. Daha kolay anlaşılması için bir örnek üzerinden gidelim. Eskiden çelik kapılarda ve kepenklerde bolca kullanılan asma kilitleri gözümüzün önüne getirelim. Şimdi bu kilitler üretildiği zaman bu kilidi açabilecek anahtar da yanında üretilip son kullanıcıya yanında veriliyor. Bana şifreli bir şekilde bir yazı veya bir dosya göndermek istediğinizi düşünelim. Görece olarak güvenli bulduğunuz bir kutuya bana göndermek istediğiniz dosyaları koyup daha sonra da benden almış olduğunuz şahsi asma kilidimi üzerine takıyorsunuz. Bu aşamada benim size vermiş olduğum tek şey bir asma kilit ve anahtarlar hala bende. Kutu kapatıldıktan ve asma kilit üzerine takıldıktan sonra asma kilidin demirlerini ittirerek içine geçirip kutuyu tamamen kilitli bir hale getiriyorsunuz. Bu aşamadan sonra size vermiş olduğum asma kilidi kullanarak kutuyu açma imkanınız yok hatta içine koyduğunuz şeyleri de artık kapattıktan sonra tekrar değiştirmeniz mümkün değil. Benim aynı asma kilitten yüzlercesine sahip olduğumu ve hepsinin aynı ve sadece bende olan bir anahtar ile açıldığını düşündüğünüzde etrafımdaki insanlara anahtarsız bir asma kilit vermenin çok da sorun olmayacağından emin olabilirsiniz. Asimetrik anahtar ile şifreleme yapılırken de gizli (private) anahtarınız ile yüzlerce genel (public) anahtar üretebilirsiniz fakat private keyiniz her zaman için tekdir. Artık benim kilidim ile kilitlenmiş kutuyu bana göndermeniz ve benim de onu kendime ait gizli anahtar ile açmam sonucunda güvenli bir şekilde bir iletişim sağlamış olduk. + +PGP’nin bize sağlamış olduğu bir anahtar ile şifreleyip sadece diğer anahtar ile o verinin açılabilmesi özelliği dönemi için çok üst düzey bir şifreleme ve güvenlik işleviydi. Şifreleme için kullanılan anahtarların uzunluğu 2048 Bit, 3072 Bit ve 4096 Bit boyutundaydı. 1 Bitin 8 Bayt olduğunu düşünürseniz bu sayıların hem bir insan için hem de o dönemin bilgisayarları için oldukça büyük sayılar olduğunu anlamışsınızdır. O dönem daha hızlı olması (düşündüğünüz kadar hızlı değil) için en düşük anahtar boyutu olan 2048 Bit kullanılmış olup genel olarak gönderilen maillerin içeriğinin (sadece içerik kısmı) ve ekte gönderilen dosyaların şifrelenmesi şeklinde kullanılmıştır. 2048 Bit yerine en yüksek anahtar boyutu olan 4096 Bit kullanıldığı zaman her ne kadar anahtar boyutu 2 kat artmış olsa da hız yerine göre 4 ile 10 kat arasında azalmaktaydı. Ortalama 200–400 karakterden oluşan bir salt yazının şifrelenmesi sırasında en düşük anahtar boyutu ile şifrelenmesi bilgisayarınızın gücüne bağlı olarak 1 ila 10 sn arasında değişebiliyordu. Bu nedenle daha uzun anahtar boyutuna sahip 4069 Bit’in şifreleme süreci çok uzun sürmekteydi. Şimdi bakıldığında 1–2 dk gibi süreler çok kısa gibi gelse de sadece bir metni göndermek için bu kadar beklemenizin gerekiyor olması o dönem için gerçekten can sıkıcıydı. Üstelik sizin şifreleme sürecinde beklediğiniz kadar da şifrelemeyi çözecek anahtara sahip kişiyi de çözüm sırasında bekletiyordunuz. + +PGP ile veri gönderilmesi ile ilgili bir örnek ile devam edelim. Mesela sizin için çok önemli olan bir veriyi göndermek istiyorsunuz. Önce farazi olarak (umarım nükleer fırlatma kodları değildir) bir yazılı metin seçelim. Benim seçtiğim veri: + +> “u, iki u daha, birincisi küçük u, ikincisi büyük u, 1 j, 3 3 3( üç tane 3 rakamı ama üçüncüsü küçük 3), yumuşak g, 6 a, k, küçük hığıı, 6 milyon. iki milyar. ama iki milyar yazıyla” ALINTI + +Önce bu veriyi… arkadaşlar yazıyı yazarken sıkıldım. Kusura bakmayın bunu da bu kadar anlatmış olayım. Ben keyfime düşkün bir adamım sıkılınca yapamıyorum. + +{{< youtube Z8aqzdARZns >}} + +NOT: Bu yazı daha önce şahsi medium.com adresimde yayımlanmıştır. Kişisel portfolyo oluşturmak adına şahsi sitemde yeniden yayımlama ihtiyacı hissettim. diff --git a/content/post/ssl-konfigurasyonu.de.md b/content/post/ssl-konfigurasyonu.de.md index ed6eee30..260a2e3d 100644 --- a/content/post/ssl-konfigurasyonu.de.md +++ b/content/post/ssl-konfigurasyonu.de.md @@ -1,138 +1,138 @@ ---- -title: "Erhöhung der SSL-Sicherheit auf Linux-Servern" -date: 2021-10-12 -tags: ["linux", "ssl", "sicherheit", "audit"] -author: "Wise" -draft: false ---- -# Erhöhung der SSL-Sicherheit auf Linux-Servern - -Wenn Sie heute eine Website und/oder App auf Ihrem aktuellen Server betreiben, werde ich über die benötigte SSL-Verbindung und die damit verbundene openssl-Bibliothek sprechen. SSL (Secure Socket Layer) und TLS (Transport Layer Security) sind eine Form der Verbindung, die es Personen, die sich mit Ihrem Server verbinden möchten, ermöglicht, sicher mit Ihrer Website zu kommunizieren. In der Vergangenheit gab es Versionen von SSL v1 bis v3, und während Websites im Allgemeinen diese SSL-Versionen verwenden, wurde SSL jetzt von den Websites aufgegeben und durch das sicherere TLS ersetzt. Wir müssen jedoch weiterhin das Wort "ssl" im erläuternden Teil und beim Bearbeiten der Konfigurationsdateien verwenden. Um Ihnen das mit ein wenig Humor zu sagen, haben Sie jemals darüber nachgedacht, warum, wenn Sie die 64-Bit-Version einer Anwendung herunterladen möchten, warum sie "amd_64" heißt? Da AMD als erster auf 64 Bit umgestiegen ist, blieb diese Namensgebung als Zeichen des Respekts und/oder der Gewohnheit bei amd_64. Auch wenn wir derzeit TLS verwenden, bleiben die Benennungs- und Konfigurationsparameter „SSL“. - -Wie in unserem vorherigen Artikel werde ich den Prozess noch einmal unter drei verschiedenen Überschriften als einfach, empfohlen und fortgeschritten erklären. Titelinhalte werden sukzessive nach persönlichen Anforderungen berücksichtigt. Obwohl die Titel miteinander verknüpft sind, ist es kein Problem, sie in einem gewünschten Stadium zu belassen. - -## Einfache Konfiguration - -Zuerst müssen wir die Updates über die Konsole mit dem Paketmanager der Linux-Version installieren, in der wir uns befinden. - -```bash -Ubuntu: sudo apt update && sudo apt upgrade -y - -Fedora: sudo yum update -y - -Arch Linux: sudo pacman -Syyu -``` - -Nachdem die Updates installiert sind, beginnen wir mit der Konfiguration des nginx/Apache-Dienstes (das ist der Dienst, der es Ihnen ermöglicht, externe Webverbindungen zu empfangen) auf Ihrem Server (in meinem Fall Ubuntu). Die Datei, in der die Nginx-Diensteinstellungen gespeichert sind, befindet sich im Allgemeinen unter „/etc/nginx/nginx.conf“. Wir müssen es mit einem der von uns verwendeten Texteditoren öffnen, jedoch mit einem Benutzer mit sudo-Rechten (dh Administratorrechten). - -Wenn wir mit Ubuntu fortfahren (Single IP for Single Server Configuration) - -```bash -sudo nano /etc/nginx/nginx.config # Befehl zum Öffnen der Einstellungsdatei -``` - -```text -Zu ergänzende Titel (gegebenenfalls geändert) -hören 443 ssl http2; >> Es dient dazu, die Anfragen zu erfüllen, die über IPv4 mit dem http2-Protokoll an Port 443 kommen, und eine SSL-Verbindung aufzubauen. - -hören [::]:443 ssl http2; >> Es dient dazu, die an Port 443 eingehenden Anfragen über IPv6 mit http2-Protokoll zu erfüllen und eine SSL-Verbindung herzustellen. (Wenn Sie keine IPv6-Unterstützung haben oder sie nicht nativ unterstützen möchten, können Sie sie entfernen.) - -server_name IHR SERVER_NAME; >> Wenn Sie Ihren Servernamen nicht als Standard festlegen möchten, können Sie einen Servernamensindikator angeben. Dies dient nur dazu, die an Ihren Servernamen eingehenden Anforderungen zu erfüllen, anstatt alle eingehenden Anforderungen zu erfüllen. - -ssl_certificate /etc/letsencrypt/live/YOURSERVER_NAME/fullchain.pem; >> Wenn Sie Let's Encrypt für kostenloses SSL verwenden, ist dies der Standardspeicherort für das Zertifikat. Andernfalls ersetzen Sie es durch Ihre eigene Zertifikatsdatei. - -ssl_certificate_key /etc/letsencrypt/live/YOURSERVER_NAME/privkey.pem; >> Wenn Sie Let's Encrypt für kostenloses SSL verwenden, ist dies der Standardspeicherort für private Schlüssel. Ersetzen Sie es andernfalls durch Ihren eigenen Speicherort der privaten Schlüsseldatei. - -ssl_protocols TLSv1.3 TLSv1.2; >> Erforderlicher Befehl, um nur die neuesten und zuverlässigsten TLS-Protokolle zu akzeptieren. - -ssl_prefer_server_ciphers on; >> Während des Gesprächs zwischen dem Server und dem Client, schätze ich, dass sie über "ok, mal sehen, was wir haben" gesprochen haben. Kurz gesagt, wenn es für Sie funktioniert, wenn es für Sie nicht funktioniert, rede ich nicht. - -ssl_ecdh_curve secp521r1:secp384r1; >> Es ist der Befehl, der uns sagt, welche Kurven wir bevorzugen, wenn wir Ekliptikkurven verwenden müssen. - -ssl_chiffren DH-RSA-AES256-SHA:DH-RSA-AES256-SHA256:DHE-RSA-AES256-GCM-SHA384:DH-RSA-AES256-GCM-SHA384:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_PODSADHESA:25_SHA256 -ECDSA-AES256 -RSA-AES256-SHA:AECDH-AES256-SHA:ECDHE-ECDSA-AES256-SHA384:ECDH-ECDSA-AES256-SHA384:ECDH-RSA-AES256-SHA384:ECDHE-ECDSA-AES256 -GCM-SHA384:ECDH-ECDSA -AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDH-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-CCM:DHE-RSA-AES256-CCM8 :ECDHE-ECDSA-AES256-CCM :ECDHE-ECDSA-AES256-CCM8:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305; >> Der Code, der den Server anweist, nur die SSL-Algorithmen zu verwenden, die ich am zuverlässigsten finde. -``` - -Alle Chiffren für diejenigen, die einzeln recherchieren wollen: "https://testssl.sh/openssl-iana.mapping.html" - -Wenn Sie nach dem Vornehmen der Einstellungen überprüfen möchten: Sie können den Befehl „sudo nginx -t“ verwenden. Wenn Sie keine Fehlermeldung sehen, können Sie die Einstellungen übernehmen und den Dienst mit dem Befehl "sudo systemctl restart nginx" oder "sudo service nginx restart" neu starten. - -## Empfohlene Einstellungen - -Zusätzlich zu den vorherigen Einstellungen werden wir einige Leistungsverbesserungen sowie einige zusätzliche Konfigurationen vornehmen, die es Ihrer Website ermöglichen, auf SSL-Testseiten einen höheren Rang einzunehmen. Danach werden wir einige Verbesserungen vornehmen, um sicherzustellen, dass einige Header und Ressourcen Ihrer Website nicht von Websites Dritter ausgenutzt werden, was für den Benutzerzugriff Ihrer Website von Vorteil ist. - -```text -Zu ergänzende Titel (gegebenenfalls geändert) -ssl_session_cache freigegeben:TLS:2m; >> Code, der angibt, wie TLS-Verbindungen auf Worker (nginx-Worker) verteilt werden und wie lange die Verbindungen geteilt werden - -ssl_buffer_size 4k; >> Der Code, der angibt, in wie viele Container die Pakete aufgeteilt werden, wenn auf SSL-Anfragen geantwortet und Pakete nach dem Handshake gesendet werden. Ein niedrigerer Wert bedeutet, dass mehr Pakete gesendet werden, aber weniger Overhead. - -ssl_stapling an; >> Aktiviert die OCSP-Heftfunktion - -ssl_stapling_verify an; Aktiviert die Möglichkeit, das OCSP-Heften zu überprüfen, einschließlich auf übergeordneten und Stammservern. - -Resolver 1.1.1.1 1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001; >> Aktiviert die OCSP-Stapling-Überprüfung mit Cloudlfare. Wenn Sie IPv6 nicht verwenden oder es nicht nativ unterstützen möchten, können Sie die IPv6-Adressen löschen. - -add_header X-Content-Type-Options "nosniff" immer; >> Es ist der Header-Wert, der Browser daran hindert, MIME-Inhalte zu verstehen. - -add_header X-Xss-Protection "1; mode=block" immer; >> Es handelt sich um einen Titel, der die Schwachstelle bis zu einem gewissen Grad verhindert, indem er Benutzern ermöglicht, einen weißen Bildschirm in einer möglichen XSS-Schwachstelle zu sehen. - -add_header X-Frame-Optionen "SAMEORIGIN" immer; >> Es verhindert in irgendeiner Weise, dass eine Seite Ihres Servers auf einer anderen Seite angezeigt und/oder nacheinander mit einem i-Frame-Code usw. veröffentlicht wird. Nur Sie können ein Fenster von Ihrer eigenen Site innerhalb Ihrer eigenen Site veröffentlichen. - -add_header Referrer-Policy "no-referrer-when-downgrade" immer; >> Wenn Sie auf eine Website mit geringeren Sicherheitsmaßnahmen umleiten oder verlinken, wird nicht automatisch ein Referrer-Header hinzugefügt und es ist nicht klar, dass der Datenverkehr von Ihrer Website kommt. - -add_header Content-Security-Policy "default-src 'self' https: data: 'unsafe-inline' 'unsafe-eval';" immer; >> Der Titel, der die Bedingungen regelt, unter denen Anfragen, die Sie und andere Benutzer von außen anrufen können, aufgerufen werden können. Standardmäßig vertraue ich einigen Quellen, die über https kommen. - -add_header Berechtigungsrichtlinie "Kamera=(), Vollbild=(self), Geolocation=(), Mikrofon=(), Zahlung=()" immer; >> Es verhindert das Sammeln von Informationen auf Ihrer Website mit verschiedenen Arten von Vergiftung (Cache-Vergiftung oder js-Vergiftung), indem es angibt, welche Berechtigungen Sie für den Browser wünschen oder welche Sie überhaupt nicht benötigen. -``` - -Wenn Sie nach dem Vornehmen der Einstellungen überprüfen möchten: Sie können den Befehl „sudo nginx -t“ verwenden. Wenn Sie keine Fehlermeldung sehen, können Sie die Einstellungen übernehmen und den Dienst mit dem Befehl „sudo systemctl restart nginx“ oder „sudo service nginx restart“ neu starten. - -## Erweiterte Einstellungen - -Zunächst fügen wir Ihrer Website einen Header hinzu, um anzuzeigen, dass sie nur über SSL verbunden werden soll. Auf diese Weise können diejenigen, die Ihre Website zuvor aufgerufen haben, und diejenigen, die diesen Titel bereits in ihrem Browser haben, nicht ohne SSL auf Ihre Website zugreifen, selbst wenn sie dies wünschen. Dann werden wir die SSL-Zertifikate heften, die in HTTP-Sitzungen verwendet werden sollen, und wir werden im Voraus angeben, welche Zertifikate neben der vorherigen Methode verbunden werden müssen. Selbst wenn Sie ein autorisierter Top-Zertifikatsmanager oder Root-Manager sind, können diese auf diese Weise keine Verbindung zu Ihrer Site mit dem in Ihrem Namen signierten Zertifikat herstellen. E-Tugra-Stammzertifikatanbieter mit Wohnsitz in der Türkei zu diesem Zeitpunkt unterzeichnete ein Zertifikat für *.google.com. Wenn Sie ein wenig recherchieren, werden Sie herausfinden, wann es passiert ist und warum (wie schlimm es sein könnte). Beginnen wir nun mit dem letzten Konfigurationsteil. - -Stellen Sie zunächst sicher, dass Ihre Website problemlos über SSL aufgerufen werden kann. Fügen Sie dann gemäß Ihrer Anfrage einen der folgenden Header zur nginx-Konfigurationsdatei hinzu. Aber Achtung, nur einer. - -```text -add_header Strict-Transport-Security "max-age=2592000;" immer; >> Header, der besagt, dass auf Ihre Website 30 Tage lang nur über HTTPS zugegriffen werden kann. (ohne Subdomains) - -add_header Strict-Transport-Security "max-age=2592000; includeSubDomains;" immer; >> Header, der besagt, dass Ihre Website 30 Tage lang nur über HTTPS aufgerufen werden kann, einschließlich Subdomains. - -add_header Strict-Transport-Security "max-age=31536000; includeSubDomains;" immer; >> Header, der besagt, dass auf Ihre Website 1 Jahr lang nur über HTTPS zugegriffen werden kann, einschließlich Subdomains. - -add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" immer; >> Der Header, der angibt, dass auf Ihre Website 1 Jahr lang nur über HTTPS zugegriffen werden kann, einschließlich Subdomains, und dass dieser Header von Browsern zwischengespeichert wird. Darüber hinaus werden neue Browser diesen Titel erkennen, auch wenn sie Ihre Website noch nie zuvor besucht haben. - -add_header Strict-Transport-Security "max-age=0; includeSubDomains"; >> Titel für das vollständige Entfernen der HSTS-Funktion und der Mitgliedschaft in der Preload-Liste. -``` - -Nachdem Sie den oben erwähnten Header hinzugefügt haben, ist es jetzt an der Zeit, den Hash des verwendeten SSL-Zertifikats an die HTTP-Sitzung anzuheften. In diesem Stadium müssen wir einen Hash Ihres aktuellen Zertifikats extrahieren, das Zertifikat der obersten Unterzeichnungsstelle hashen und diesen Hash-Prozess fortsetzen, bis wir die gesamte Kette einschließlich der obersten Stammzertifizierungsstelle abgeschlossen haben. Aus diesem Grund führen wir die folgenden Befehle jeweils mit einem Root-Benutzer oder einem Benutzer mit sudo-Berechtigung aus. (Der Vortrag wurde speziell für Let's Encrypt gemacht.) - -```bash -1] cat /etc/letsencrypt/live/IHR SERVERNAME/cert.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binär | base64 >> Dieser Befehl extrahiert den Hash des Zertifikats Ihrer Website. Kopieren Sie den Ergebniswert irgendwo hin. -2] curl -s https://letsencrypt.org/certs/lets-encrypt-x4-cross-signed.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binär | base64 >> Dieser Befehl extrahiert eines der mehrfach signierten Zertifikate von letsencrypt. -3] curl -s https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binär | base64 >> Dieser Befehl extrahiert eines der mehrfach signierten Zertifikate von letsencrypt. -4] curl -s https://letsencrypt.org/certs/isrgrootx1.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binär | base64 >> Dieser Befehl extrahiert das Stammzertifikat (oberstes Zertifikat) von letsencrypt. - -Der folgende Wert wird der Nginx-Konfigurationsdatei hinzugefügt -5] add_header Public-Key-Pins 'pin-sha256="ERSTE_ERGEBNIS"; Pin-sha256 = "ZWEITES_ERGEBNIS"; pin-sha256="TIP_END"; pin-sha256="FINISH_RESULT"; Maximalalter = 2592000; includeSubDomains' immer; >> Sie können sich nur mit dem angegebenen Zertifikat 30 Tage lang mit Ihrer Website verbinden. Sie können den max-age-Wert optional erhöhen. Bevor die Gültigkeitsdauer Ihres Zertifikats weniger als 30 Tage beträgt, müssen Sie die Kopfzeile deaktivieren oder ein neues Zertifikat anfordern und es als fünften Wert hinzufügen. - -Als Bonus möchte ich Ihnen einen weiteren Befehl zeigen, dessen Ausführung lange dauert, aber sehr nützlich ist. -6] openssl dhparam -out /etc/nginx/dhparams.pem 4096 >> Die Ausführung dieses Befehls kann zwischen 15 Minuten und 1 Stunde dauern. - -Nachdem der Vorgang abgeschlossen ist, müssen Sie den folgenden Befehl zur nginx-Konfigurationsdatei hinzufügen. -ssl_dhparam /etc/nginx/dhparam.pem; >> Der Befehl zum Ändern der während des Diffie-Hellman-Schlüsselaustauschalgorithmus zu verwendenden Werte mit den gerade erstellten geheimen Werten, abgesehen von den Standardwerten. -``` - -Nachdem Sie die Einstellungen vorgenommen haben, übernehmen Sie die Einstellungen mit dem Befehl „sudo nginx -t“ und dann, wenn Sie keine Fehlermeldung sehen, „sudo service nginx restart“ und starten Sie den Dienst neu. Nun wird die Verbindung mit der von Ihnen festgelegten Konfiguration und Bedingungen bereitgestellt. Wenn Sie den Vorher/Nachher-Bewertungsunterschied sehen möchten, können Sie sich die Bilder unten ansehen oder Ihre eigene Website unter „ testen. - -VOR -![SSL Labs test](/images/ssl-anlatim/ssl-ilk-hali-ssllabs.png) - -NACH -![SSL Labs test](/images/ssl-anlatim/ssl-son-hali-ssllabs.png) - -Wenn Sie fragen, warum die Cipher-Stärke nicht 100 % beträgt, ist es derzeit nicht möglich, 100 % zu erreichen, da „TLS_AES_128_GCM_SHA256 (0x1301)“ automatisch mit TLS 1.3 geliefert wird und hinzugefügt wird, auch wenn wir es nicht möchten. Wenn Sie denken, dass ich TLS 1.3 abschalte, dann wird es nicht kommen, dann sind Ihre Punkte leider woanders weg. - -# Ende - -Dieser Artikel wurde zuvor unter veröffentlicht. Um ein persönliches Portfolio zu erstellen, hatte ich das Bedürfnis, es auf meiner persönlichen Website erneut zu veröffentlichen. +--- +title: "Erhöhung der SSL-Sicherheit auf Linux-Servern" +date: 2021-10-12 +tags: ["linux", "ssl", "sicherheit", "audit"] +author: "Wise" +draft: false +--- +# Erhöhung der SSL-Sicherheit auf Linux-Servern + +Wenn Sie heute eine Website und/oder App auf Ihrem aktuellen Server betreiben, werde ich über die benötigte SSL-Verbindung und die damit verbundene openssl-Bibliothek sprechen. SSL (Secure Socket Layer) und TLS (Transport Layer Security) sind eine Form der Verbindung, die es Personen, die sich mit Ihrem Server verbinden möchten, ermöglicht, sicher mit Ihrer Website zu kommunizieren. In der Vergangenheit gab es Versionen von SSL v1 bis v3, und während Websites im Allgemeinen diese SSL-Versionen verwenden, wurde SSL jetzt von den Websites aufgegeben und durch das sicherere TLS ersetzt. Wir müssen jedoch weiterhin das Wort "ssl" im erläuternden Teil und beim Bearbeiten der Konfigurationsdateien verwenden. Um Ihnen das mit ein wenig Humor zu sagen, haben Sie jemals darüber nachgedacht, warum, wenn Sie die 64-Bit-Version einer Anwendung herunterladen möchten, warum sie "amd_64" heißt? Da AMD als erster auf 64 Bit umgestiegen ist, blieb diese Namensgebung als Zeichen des Respekts und/oder der Gewohnheit bei amd_64. Auch wenn wir derzeit TLS verwenden, bleiben die Benennungs- und Konfigurationsparameter „SSL“. + +Wie in unserem vorherigen Artikel werde ich den Prozess noch einmal unter drei verschiedenen Überschriften als einfach, empfohlen und fortgeschritten erklären. Titelinhalte werden sukzessive nach persönlichen Anforderungen berücksichtigt. Obwohl die Titel miteinander verknüpft sind, ist es kein Problem, sie in einem gewünschten Stadium zu belassen. + +## Einfache Konfiguration + +Zuerst müssen wir die Updates über die Konsole mit dem Paketmanager der Linux-Version installieren, in der wir uns befinden. + +```bash +Ubuntu: sudo apt update && sudo apt upgrade -y + +Fedora: sudo yum update -y + +Arch Linux: sudo pacman -Syyu +``` + +Nachdem die Updates installiert sind, beginnen wir mit der Konfiguration des nginx/Apache-Dienstes (das ist der Dienst, der es Ihnen ermöglicht, externe Webverbindungen zu empfangen) auf Ihrem Server (in meinem Fall Ubuntu). Die Datei, in der die Nginx-Diensteinstellungen gespeichert sind, befindet sich im Allgemeinen unter „/etc/nginx/nginx.conf“. Wir müssen es mit einem der von uns verwendeten Texteditoren öffnen, jedoch mit einem Benutzer mit sudo-Rechten (dh Administratorrechten). + +Wenn wir mit Ubuntu fortfahren (Single IP for Single Server Configuration) + +```bash +sudo nano /etc/nginx/nginx.config # Befehl zum Öffnen der Einstellungsdatei +``` + +```text +Zu ergänzende Titel (gegebenenfalls geändert) +hören 443 ssl http2; >> Es dient dazu, die Anfragen zu erfüllen, die über IPv4 mit dem http2-Protokoll an Port 443 kommen, und eine SSL-Verbindung aufzubauen. + +hören [::]:443 ssl http2; >> Es dient dazu, die an Port 443 eingehenden Anfragen über IPv6 mit http2-Protokoll zu erfüllen und eine SSL-Verbindung herzustellen. (Wenn Sie keine IPv6-Unterstützung haben oder sie nicht nativ unterstützen möchten, können Sie sie entfernen.) + +server_name IHR SERVER_NAME; >> Wenn Sie Ihren Servernamen nicht als Standard festlegen möchten, können Sie einen Servernamensindikator angeben. Dies dient nur dazu, die an Ihren Servernamen eingehenden Anforderungen zu erfüllen, anstatt alle eingehenden Anforderungen zu erfüllen. + +ssl_certificate /etc/letsencrypt/live/YOURSERVER_NAME/fullchain.pem; >> Wenn Sie Let's Encrypt für kostenloses SSL verwenden, ist dies der Standardspeicherort für das Zertifikat. Andernfalls ersetzen Sie es durch Ihre eigene Zertifikatsdatei. + +ssl_certificate_key /etc/letsencrypt/live/YOURSERVER_NAME/privkey.pem; >> Wenn Sie Let's Encrypt für kostenloses SSL verwenden, ist dies der Standardspeicherort für private Schlüssel. Ersetzen Sie es andernfalls durch Ihren eigenen Speicherort der privaten Schlüsseldatei. + +ssl_protocols TLSv1.3 TLSv1.2; >> Erforderlicher Befehl, um nur die neuesten und zuverlässigsten TLS-Protokolle zu akzeptieren. + +ssl_prefer_server_ciphers on; >> Während des Gesprächs zwischen dem Server und dem Client, schätze ich, dass sie über "ok, mal sehen, was wir haben" gesprochen haben. Kurz gesagt, wenn es für Sie funktioniert, wenn es für Sie nicht funktioniert, rede ich nicht. + +ssl_ecdh_curve secp521r1:secp384r1; >> Es ist der Befehl, der uns sagt, welche Kurven wir bevorzugen, wenn wir Ekliptikkurven verwenden müssen. + +ssl_chiffren DH-RSA-AES256-SHA:DH-RSA-AES256-SHA256:DHE-RSA-AES256-GCM-SHA384:DH-RSA-AES256-GCM-SHA384:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_PODSADHESA:25_SHA256 -ECDSA-AES256 -RSA-AES256-SHA:AECDH-AES256-SHA:ECDHE-ECDSA-AES256-SHA384:ECDH-ECDSA-AES256-SHA384:ECDH-RSA-AES256-SHA384:ECDHE-ECDSA-AES256 -GCM-SHA384:ECDH-ECDSA -AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDH-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-CCM:DHE-RSA-AES256-CCM8 :ECDHE-ECDSA-AES256-CCM :ECDHE-ECDSA-AES256-CCM8:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305; >> Der Code, der den Server anweist, nur die SSL-Algorithmen zu verwenden, die ich am zuverlässigsten finde. +``` + +Alle Chiffren für diejenigen, die einzeln recherchieren wollen: "https://testssl.sh/openssl-iana.mapping.html" + +Wenn Sie nach dem Vornehmen der Einstellungen überprüfen möchten: Sie können den Befehl „sudo nginx -t“ verwenden. Wenn Sie keine Fehlermeldung sehen, können Sie die Einstellungen übernehmen und den Dienst mit dem Befehl "sudo systemctl restart nginx" oder "sudo service nginx restart" neu starten. + +## Empfohlene Einstellungen + +Zusätzlich zu den vorherigen Einstellungen werden wir einige Leistungsverbesserungen sowie einige zusätzliche Konfigurationen vornehmen, die es Ihrer Website ermöglichen, auf SSL-Testseiten einen höheren Rang einzunehmen. Danach werden wir einige Verbesserungen vornehmen, um sicherzustellen, dass einige Header und Ressourcen Ihrer Website nicht von Websites Dritter ausgenutzt werden, was für den Benutzerzugriff Ihrer Website von Vorteil ist. + +```text +Zu ergänzende Titel (gegebenenfalls geändert) +ssl_session_cache freigegeben:TLS:2m; >> Code, der angibt, wie TLS-Verbindungen auf Worker (nginx-Worker) verteilt werden und wie lange die Verbindungen geteilt werden + +ssl_buffer_size 4k; >> Der Code, der angibt, in wie viele Container die Pakete aufgeteilt werden, wenn auf SSL-Anfragen geantwortet und Pakete nach dem Handshake gesendet werden. Ein niedrigerer Wert bedeutet, dass mehr Pakete gesendet werden, aber weniger Overhead. + +ssl_stapling an; >> Aktiviert die OCSP-Heftfunktion + +ssl_stapling_verify an; Aktiviert die Möglichkeit, das OCSP-Heften zu überprüfen, einschließlich auf übergeordneten und Stammservern. + +Resolver 1.1.1.1 1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001; >> Aktiviert die OCSP-Stapling-Überprüfung mit Cloudlfare. Wenn Sie IPv6 nicht verwenden oder es nicht nativ unterstützen möchten, können Sie die IPv6-Adressen löschen. + +add_header X-Content-Type-Options "nosniff" immer; >> Es ist der Header-Wert, der Browser daran hindert, MIME-Inhalte zu verstehen. + +add_header X-Xss-Protection "1; mode=block" immer; >> Es handelt sich um einen Titel, der die Schwachstelle bis zu einem gewissen Grad verhindert, indem er Benutzern ermöglicht, einen weißen Bildschirm in einer möglichen XSS-Schwachstelle zu sehen. + +add_header X-Frame-Optionen "SAMEORIGIN" immer; >> Es verhindert in irgendeiner Weise, dass eine Seite Ihres Servers auf einer anderen Seite angezeigt und/oder nacheinander mit einem i-Frame-Code usw. veröffentlicht wird. Nur Sie können ein Fenster von Ihrer eigenen Site innerhalb Ihrer eigenen Site veröffentlichen. + +add_header Referrer-Policy "no-referrer-when-downgrade" immer; >> Wenn Sie auf eine Website mit geringeren Sicherheitsmaßnahmen umleiten oder verlinken, wird nicht automatisch ein Referrer-Header hinzugefügt und es ist nicht klar, dass der Datenverkehr von Ihrer Website kommt. + +add_header Content-Security-Policy "default-src 'self' https: data: 'unsafe-inline' 'unsafe-eval';" immer; >> Der Titel, der die Bedingungen regelt, unter denen Anfragen, die Sie und andere Benutzer von außen anrufen können, aufgerufen werden können. Standardmäßig vertraue ich einigen Quellen, die über https kommen. + +add_header Berechtigungsrichtlinie "Kamera=(), Vollbild=(self), Geolocation=(), Mikrofon=(), Zahlung=()" immer; >> Es verhindert das Sammeln von Informationen auf Ihrer Website mit verschiedenen Arten von Vergiftung (Cache-Vergiftung oder js-Vergiftung), indem es angibt, welche Berechtigungen Sie für den Browser wünschen oder welche Sie überhaupt nicht benötigen. +``` + +Wenn Sie nach dem Vornehmen der Einstellungen überprüfen möchten: Sie können den Befehl „sudo nginx -t“ verwenden. Wenn Sie keine Fehlermeldung sehen, können Sie die Einstellungen übernehmen und den Dienst mit dem Befehl „sudo systemctl restart nginx“ oder „sudo service nginx restart“ neu starten. + +## Erweiterte Einstellungen + +Zunächst fügen wir Ihrer Website einen Header hinzu, um anzuzeigen, dass sie nur über SSL verbunden werden soll. Auf diese Weise können diejenigen, die Ihre Website zuvor aufgerufen haben, und diejenigen, die diesen Titel bereits in ihrem Browser haben, nicht ohne SSL auf Ihre Website zugreifen, selbst wenn sie dies wünschen. Dann werden wir die SSL-Zertifikate heften, die in HTTP-Sitzungen verwendet werden sollen, und wir werden im Voraus angeben, welche Zertifikate neben der vorherigen Methode verbunden werden müssen. Selbst wenn Sie ein autorisierter Top-Zertifikatsmanager oder Root-Manager sind, können diese auf diese Weise keine Verbindung zu Ihrer Site mit dem in Ihrem Namen signierten Zertifikat herstellen. E-Tugra-Stammzertifikatanbieter mit Wohnsitz in der Türkei zu diesem Zeitpunkt unterzeichnete ein Zertifikat für *.google.com. Wenn Sie ein wenig recherchieren, werden Sie herausfinden, wann es passiert ist und warum (wie schlimm es sein könnte). Beginnen wir nun mit dem letzten Konfigurationsteil. + +Stellen Sie zunächst sicher, dass Ihre Website problemlos über SSL aufgerufen werden kann. Fügen Sie dann gemäß Ihrer Anfrage einen der folgenden Header zur nginx-Konfigurationsdatei hinzu. Aber Achtung, nur einer. + +```text +add_header Strict-Transport-Security "max-age=2592000;" immer; >> Header, der besagt, dass auf Ihre Website 30 Tage lang nur über HTTPS zugegriffen werden kann. (ohne Subdomains) + +add_header Strict-Transport-Security "max-age=2592000; includeSubDomains;" immer; >> Header, der besagt, dass Ihre Website 30 Tage lang nur über HTTPS aufgerufen werden kann, einschließlich Subdomains. + +add_header Strict-Transport-Security "max-age=31536000; includeSubDomains;" immer; >> Header, der besagt, dass auf Ihre Website 1 Jahr lang nur über HTTPS zugegriffen werden kann, einschließlich Subdomains. + +add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" immer; >> Der Header, der angibt, dass auf Ihre Website 1 Jahr lang nur über HTTPS zugegriffen werden kann, einschließlich Subdomains, und dass dieser Header von Browsern zwischengespeichert wird. Darüber hinaus werden neue Browser diesen Titel erkennen, auch wenn sie Ihre Website noch nie zuvor besucht haben. + +add_header Strict-Transport-Security "max-age=0; includeSubDomains"; >> Titel für das vollständige Entfernen der HSTS-Funktion und der Mitgliedschaft in der Preload-Liste. +``` + +Nachdem Sie den oben erwähnten Header hinzugefügt haben, ist es jetzt an der Zeit, den Hash des verwendeten SSL-Zertifikats an die HTTP-Sitzung anzuheften. In diesem Stadium müssen wir einen Hash Ihres aktuellen Zertifikats extrahieren, das Zertifikat der obersten Unterzeichnungsstelle hashen und diesen Hash-Prozess fortsetzen, bis wir die gesamte Kette einschließlich der obersten Stammzertifizierungsstelle abgeschlossen haben. Aus diesem Grund führen wir die folgenden Befehle jeweils mit einem Root-Benutzer oder einem Benutzer mit sudo-Berechtigung aus. (Der Vortrag wurde speziell für Let's Encrypt gemacht.) + +```bash +1] cat /etc/letsencrypt/live/IHR SERVERNAME/cert.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binär | base64 >> Dieser Befehl extrahiert den Hash des Zertifikats Ihrer Website. Kopieren Sie den Ergebniswert irgendwo hin. +2] curl -s https://letsencrypt.org/certs/lets-encrypt-x4-cross-signed.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binär | base64 >> Dieser Befehl extrahiert eines der mehrfach signierten Zertifikate von letsencrypt. +3] curl -s https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binär | base64 >> Dieser Befehl extrahiert eines der mehrfach signierten Zertifikate von letsencrypt. +4] curl -s https://letsencrypt.org/certs/isrgrootx1.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binär | base64 >> Dieser Befehl extrahiert das Stammzertifikat (oberstes Zertifikat) von letsencrypt. + +Der folgende Wert wird der Nginx-Konfigurationsdatei hinzugefügt +5] add_header Public-Key-Pins 'pin-sha256="ERSTE_ERGEBNIS"; Pin-sha256 = "ZWEITES_ERGEBNIS"; pin-sha256="TIP_END"; pin-sha256="FINISH_RESULT"; Maximalalter = 2592000; includeSubDomains' immer; >> Sie können sich nur mit dem angegebenen Zertifikat 30 Tage lang mit Ihrer Website verbinden. Sie können den max-age-Wert optional erhöhen. Bevor die Gültigkeitsdauer Ihres Zertifikats weniger als 30 Tage beträgt, müssen Sie die Kopfzeile deaktivieren oder ein neues Zertifikat anfordern und es als fünften Wert hinzufügen. + +Als Bonus möchte ich Ihnen einen weiteren Befehl zeigen, dessen Ausführung lange dauert, aber sehr nützlich ist. +6] openssl dhparam -out /etc/nginx/dhparams.pem 4096 >> Die Ausführung dieses Befehls kann zwischen 15 Minuten und 1 Stunde dauern. + +Nachdem der Vorgang abgeschlossen ist, müssen Sie den folgenden Befehl zur nginx-Konfigurationsdatei hinzufügen. +ssl_dhparam /etc/nginx/dhparam.pem; >> Der Befehl zum Ändern der während des Diffie-Hellman-Schlüsselaustauschalgorithmus zu verwendenden Werte mit den gerade erstellten geheimen Werten, abgesehen von den Standardwerten. +``` + +Nachdem Sie die Einstellungen vorgenommen haben, übernehmen Sie die Einstellungen mit dem Befehl „sudo nginx -t“ und dann, wenn Sie keine Fehlermeldung sehen, „sudo service nginx restart“ und starten Sie den Dienst neu. Nun wird die Verbindung mit der von Ihnen festgelegten Konfiguration und Bedingungen bereitgestellt. Wenn Sie den Vorher/Nachher-Bewertungsunterschied sehen möchten, können Sie sich die Bilder unten ansehen oder Ihre eigene Website unter „ testen. + +VOR +![SSL Labs test](/images/ssl-anlatim/ssl-ilk-hali-ssllabs.png) + +NACH +![SSL Labs test](/images/ssl-anlatim/ssl-son-hali-ssllabs.png) + +Wenn Sie fragen, warum die Cipher-Stärke nicht 100 % beträgt, ist es derzeit nicht möglich, 100 % zu erreichen, da „TLS_AES_128_GCM_SHA256 (0x1301)“ automatisch mit TLS 1.3 geliefert wird und hinzugefügt wird, auch wenn wir es nicht möchten. Wenn Sie denken, dass ich TLS 1.3 abschalte, dann wird es nicht kommen, dann sind Ihre Punkte leider woanders weg. + +# Ende + +Dieser Artikel wurde zuvor unter veröffentlicht. Um ein persönliches Portfolio zu erstellen, hatte ich das Bedürfnis, es auf meiner persönlichen Website erneut zu veröffentlichen. diff --git a/content/post/ssl-konfigurasyonu.en.md b/content/post/ssl-konfigurasyonu.en.md index 1607fc5e..78feccb2 100644 --- a/content/post/ssl-konfigurasyonu.en.md +++ b/content/post/ssl-konfigurasyonu.en.md @@ -1,138 +1,138 @@ ---- -title: "Increasing SSL security on Linux Servers" -date: 2021-10-12 -tags: ["linux", "ssl", "security", "audit"] -author: "Wise" -draft: false ---- -# Increasing SSL security on Linux Servers - -Today, if you are serving a website and/or App on your current server, I will talk about the SSL connection you need and the openssl library in connection with it. SSL (Secure Socket Layer) and TLS (Transport Layer Security) are a form of connection that allows people who want to connect to your server to communicate securely with your site. There are versions ranging from SSL v1-v3 in the past, and while sites generally use these SSL versions, SSL has now been abandoned by the sites and has been replaced by the more secure TLS. However, we will still need to use the word "ssl" in the narrative part and while editing the config files. To tell you this with a little humor, have you ever thought why when you want to download the 64 bit version of an application, why it is called "amd_64"? Because AMD was the first to switch to 64 bit, this naming remained as amd_64 as a sign of respect and/or habit. Likewise, although we are currently using TLS, the naming and configuration parameters remain "SSL". - -As in our previous article, I will explain the process again under three different headings as simple, recommended and advanced. Title contents are gradually considered according to personal requirements. Although the titles are linked to each other, leaving them at a desired stage will not pose a problem. - -## Simple configuration - -First of all, we need to install the updates via the console with the package manager of the Linux version we are in. - -```bash -Ubuntu: sudo apt update && sudo apt upgrade -y - -Fedora: sudo yum update -y - -Arch Linux: sudo pacman -Syyu -``` - -After the updates are installed, we start configuring the nginx/apache service (which is the service that allows you to receive external web connections) on your server (Ubuntu in my case). The file where the Nginx service settings are kept is generally located at "/etc/nginx/nginx.conf". We need to open it with any of the text editors we use, but with a user with sudo (ie administrator) privileges. - -If we continue on Ubuntu (Single IP for Single Server Configuration) - -```bash -sudo nano /etc/nginx/nginx.config # Command to open the settings file -``` - -```text -Titles to be added (changed if any) -listen 443 ssl http2; >> It serves to meet the requests coming to port 443 via ipv4 with http2 protocol and establish ssl connection. - -listen [::]:443 ssl http2; >> It serves to meet the requests coming to port 443 over ipv6 with http2 protocol and establish ssl connection. (If you don't have ipv6 support or you don't want to support it natively, you can remove it) - -server_name YOUR SERVER_NAME; >> If you do not want to set your server name as default, you can specify a Server Name Indicator. This only serves to meet the requests coming to your server name instead of meeting all incoming requests. - -ssl_certificate /etc/letsencrypt/live/YOURSERVER_NAME/fullchain.pem; >> If you are using Let's Encrypt for free ssl, this is the default certificate location. Otherwise, replace it with your own certificate file. - -ssl_certificate_key /etc/letsencrypt/live/YOURSERVER_NAME/privkey.pem; >> If you are using Let's Encrypt for free ssl, this is the default private key location. Otherwise replace it with your own private key file location. - -ssl_protocols TLSv1.3 TLSv1.2; >> Required command to accept only the latest and most reliable TLS protocols. - -ssl_prefer_server_ciphers on; >> During the conversation between the server and the client, I guess that they were talking about "ok, let's see what we have". In short, if it works for you, if it doesn't work for you, I don't talk. - -ssl_ecdh_curve secp521r1:secp384r1; >> It is the command that tells us which curves we prefer when we need to use ecliptic curves. - -ssl_ciphers DH-RSA-AES256-SHA:DH-RSA-AES256-SHA256:DHE-RSA-AES256-GCM-SHA384:DH-RSA-AES256-GCM-SHA384:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_PODSADHESA:25_SHA256 -ECDSA-AES256-SHA:ECDH-RSA-AES256-SHA:AECDH-AES256-SHA:ECDHE-ECDSA-AES256-SHA384:ECDH-ECDSA-AES256-SHA384:ECDH-RSA-AES256-SHA384:ECDHE-ECDSA-AES256 -GCM-SHA384:ECDH-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDH-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-CCM:DHE-RSA-AES256-CCM8 :ECDHE-ECDSA-AES256-CCM:ECDHE-ECDSA-AES256-CCM8:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305; >> The code that tells the server to use only those SSL algorithms that I find the most reliable. -``` - -All ciphers for those who want to research one by one: "https://testssl.sh/openssl-iana.mapping.html" - -If you want to check after making the settings: You can use the command "sudo nginx -t". If you do not see an error message, you can apply the settings and restart the service with the command "sudo systemctl restart nginx" or "sudo service nginx restart" - -## Recommended settings - -In addition to the previous settings, we will make some performance improvements, as well as some additional configurations that will enable your site to rank higher in SSL test sites. After that, we will make some improvements to ensure that some headers and resources of your site are not exploited by third party sites, which will be beneficial for your site's user access. - -```text -Titles to be added (changed if any) -ssl_session_cache shared:TLS:2m; >> Code specifying how TLS connections will be distributed among workers (nginx workers) and for how long the connections will be shared - -ssl_buffer_size 4k; >> The code that indicates how many containers the packets will be divided into when responding to SSL requests and sending packets after handshake. A lower value means more packets are sent but less overhead. - -ssl_stapling on; >> Activates the OCSP stapling feature - -ssl_stapling_verify on; Turns on the ability to verify OCSP stapling, including on parent and root servers. - -resolver 1.1.1.1 1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001; >> Enables OCSP stapling verification with Cloudlfare. If you do not use IPV6 or do not want to support it natively, you can delete the IPv6 addresses. - -add_header X-Content-Type-Options "nosniff" always; >> It is the header value that prevents browsers from sniffing to understand MIME contents. - -add_header X-Xss-Protection "1; mode=block" always; >> It is a title that prevents the vulnerability to some extent by allowing users to see a white screen in a possible XSS vulnerability. - -add_header X-Frame-Options "SAMEORIGIN" always; >> It prevents a page of your server from being shown on another page and/or being published one after the other with an i-frame etc. code in any way. Only you can publish a window from your own site within your own site. - -add_header Referrer-Policy "no-referrer-when-downgrade" always; >> When you redirect or link to a site with lower security measures, it does not automatically add a referrer header and it is not clear that traffic is coming from your site. - -add_header Content-Security-Policy "default-src 'self' https: data: 'unsafe-inline' 'unsafe-eval';" always; >> The title that regulates the conditions under which requests that you and other users can call from outside can be called. By default, I trust some sources that come over https. - -add_header Permissions-Policy "camera=(), fullscreen=(self), geolocation=(), microphone=(), payment=()" always; >> It prevents the collection of information on your site with various types of poisoning (cache-poisoning or js-poisoning) by specifying which permissions you will want to the browser or which you will not need at all. -``` - -If you want to check after making the settings: You can use the command "sudo nginx -t". If you do not see an error message, you can apply the settings and restart the service with the command "sudo systemctl restart nginx" or "sudo service nginx restart". - -## Advanced Settings - -First, we'll add a header to your site to indicate that it should only be connected via ssl. In this way, those who have entered your site before and those who already have this title in their browser will not be able to access your site non-SSL even if they want it. Then we will staple the SSL certificates that should be used in HTTP sessions, and we will specify in advance which certificates will need to be connected next to the previous method. In this way, even if you are an authorized top certificate manager or root manager, they will not be able to connect to your site with the certificate signed on your behalf. E-Tugra Root Certificate provider residing in Turkey at the time signed a certificate to *.google.com. If you do a little research, you'll find out when it happened and why (how bad it could cause). Now let's start the final configuration part. - -First, make sure that your site can be accessed over SSL without causing any problems. Then add one of the following headers to the nginx config file as per your request. But beware, only one. - -```text -add_header Strict-Transport-Security "max-age=2592000;" always; >> Header stating that your site can only be accessed over HTTPS for 30 days. (Not including subdomains) - -add_header Strict-Transport-Security "max-age=2592000; includeSubDomains;" always; >> Header stating that your site can only be accessed over HTTPS for 30 days, including subdomains. - -add_header Strict-Transport-Security "max-age=31536000; includeSubDomains;" always; >> Header stating that your site can only be accessed over HTTPS for 1 year, including subdomains. - -add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; >> The header that instructs that your site can only be accessed over HTTPS for 1 year, including subdomains, and that this header is cached by browsers. In addition, new browsers will be aware of this title even if they have never visited your site before. - -add_header Strict-Transport-Security "max-age=0; includeSubDomains"; >> Title for removing HSTS feature and preload list membership completely. -``` - -After adding the header mentioned above, now it's time to staple the hash of the ssl certificate you used to the HTTP session. At this stage we need to extract a hash of your current certificate, hash the top signing authority's certificate, and continue this hashing process until we've completed the entire chain, including the top root certificate authority. For this reason, we run the following commands respectively with a root user or a user with sudo authority. (The lecture was made specifically for Let's Encrypt.) - -```bash -1] cat /etc/letsencrypt/live/YOUR SERVER_NAME/cert.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 >> This command will extract the hash of your site's certificate. Copy the result value somewhere. -2] curl -s https://letsencrypt.org/certs/lets-encrypt-x4-cross-signed.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 >> This command will extract one of the multi-signed certificates of letsencrypt. -3] curl -s https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 >> This command will extract one of the multi-signed certificates of letsencrypt. -4] curl -s https://letsencrypt.org/certs/isrgrootx1.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 >> This command will extract the root (top) certificate of letsencrypt. - -The following value is added to the Nginx config file -5] add_header Public-Key-Pins 'pin-sha256="FIRST_RESULT"; pin-sha256="SECOND_RESULT"; pin-sha256="TIP_END"; pin-sha256="FINISH_RESULT"; max-age=2592000; includeSubDomains' always; >> Allows you to connect to your site for 30 days only with the specified certificate. You can optionally increase the max-age value. Before your certificate validity period is less than 30 days, you must disable the header or obtain a new certificate and add it as the fifth value. - -As a bonus, I'd like to show you another command that will take a long time for your server to execute, but is very useful. -6] openssl dhparam -out /etc/nginx/dhparams.pem 4096 >> This command can take between 15 minutes and 1 hour to execute. - -After the process is finished, you need to add the following command to the nginx config file. -ssl_dhparam /etc/nginx/dhparam.pem; >> The command to change the values ​​to be used during the Diffie-Hellman key exchange algorithm with the secret values ​​we just created, apart from the default values. -``` - -After making the settings, apply the settings with the command "sudo nginx -t" and then, if you do not see an error message, "sudo service nginx restart" and restart the service. Now the connection will be provided with the configuration and conditions you have specified. If you want to see the before/after scoring difference, you can look at the images below or test your own site at "https://www.ssllabs.com/ssltest/index.html". - -BEFORE -![SSL Labs test result](/images/ssl-anlatim/ssl-ilk-hali-ssllabs.png) - -AFTER -![SSL Labs test result](/images/ssl-anlatim/ssl-son-hali-ssllabs.png) - -If you ask why Cipher Strength is not 100%, it is not possible to make 100% at the moment because of the "TLS_AES_128_GCM_SHA256 (0x1301)" that comes automatically with TLS 1.3 and is added even if we don't want it. If you think that I will turn off TLS 1.3, then it will not come, then unfortunately your points are gone from somewhere else. - -# End - -This article was previously published at . In order to create a personal portfolio, I felt the need to republish it on my personal site. +--- +title: "Increasing SSL security on Linux Servers" +date: 2021-10-12 +tags: ["linux", "ssl", "security", "audit"] +author: "Wise" +draft: false +--- +# Increasing SSL security on Linux Servers + +Today, if you are serving a website and/or App on your current server, I will talk about the SSL connection you need and the openssl library in connection with it. SSL (Secure Socket Layer) and TLS (Transport Layer Security) are a form of connection that allows people who want to connect to your server to communicate securely with your site. There are versions ranging from SSL v1-v3 in the past, and while sites generally use these SSL versions, SSL has now been abandoned by the sites and has been replaced by the more secure TLS. However, we will still need to use the word "ssl" in the narrative part and while editing the config files. To tell you this with a little humor, have you ever thought why when you want to download the 64 bit version of an application, why it is called "amd_64"? Because AMD was the first to switch to 64 bit, this naming remained as amd_64 as a sign of respect and/or habit. Likewise, although we are currently using TLS, the naming and configuration parameters remain "SSL". + +As in our previous article, I will explain the process again under three different headings as simple, recommended and advanced. Title contents are gradually considered according to personal requirements. Although the titles are linked to each other, leaving them at a desired stage will not pose a problem. + +## Simple configuration + +First of all, we need to install the updates via the console with the package manager of the Linux version we are in. + +```bash +Ubuntu: sudo apt update && sudo apt upgrade -y + +Fedora: sudo yum update -y + +Arch Linux: sudo pacman -Syyu +``` + +After the updates are installed, we start configuring the nginx/apache service (which is the service that allows you to receive external web connections) on your server (Ubuntu in my case). The file where the Nginx service settings are kept is generally located at "/etc/nginx/nginx.conf". We need to open it with any of the text editors we use, but with a user with sudo (ie administrator) privileges. + +If we continue on Ubuntu (Single IP for Single Server Configuration) + +```bash +sudo nano /etc/nginx/nginx.config # Command to open the settings file +``` + +```text +Titles to be added (changed if any) +listen 443 ssl http2; >> It serves to meet the requests coming to port 443 via ipv4 with http2 protocol and establish ssl connection. + +listen [::]:443 ssl http2; >> It serves to meet the requests coming to port 443 over ipv6 with http2 protocol and establish ssl connection. (If you don't have ipv6 support or you don't want to support it natively, you can remove it) + +server_name YOUR SERVER_NAME; >> If you do not want to set your server name as default, you can specify a Server Name Indicator. This only serves to meet the requests coming to your server name instead of meeting all incoming requests. + +ssl_certificate /etc/letsencrypt/live/YOURSERVER_NAME/fullchain.pem; >> If you are using Let's Encrypt for free ssl, this is the default certificate location. Otherwise, replace it with your own certificate file. + +ssl_certificate_key /etc/letsencrypt/live/YOURSERVER_NAME/privkey.pem; >> If you are using Let's Encrypt for free ssl, this is the default private key location. Otherwise replace it with your own private key file location. + +ssl_protocols TLSv1.3 TLSv1.2; >> Required command to accept only the latest and most reliable TLS protocols. + +ssl_prefer_server_ciphers on; >> During the conversation between the server and the client, I guess that they were talking about "ok, let's see what we have". In short, if it works for you, if it doesn't work for you, I don't talk. + +ssl_ecdh_curve secp521r1:secp384r1; >> It is the command that tells us which curves we prefer when we need to use ecliptic curves. + +ssl_ciphers DH-RSA-AES256-SHA:DH-RSA-AES256-SHA256:DHE-RSA-AES256-GCM-SHA384:DH-RSA-AES256-GCM-SHA384:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_PODSADHESA:25_SHA256 -ECDSA-AES256-SHA:ECDH-RSA-AES256-SHA:AECDH-AES256-SHA:ECDHE-ECDSA-AES256-SHA384:ECDH-ECDSA-AES256-SHA384:ECDH-RSA-AES256-SHA384:ECDHE-ECDSA-AES256 -GCM-SHA384:ECDH-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDH-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-CCM:DHE-RSA-AES256-CCM8 :ECDHE-ECDSA-AES256-CCM:ECDHE-ECDSA-AES256-CCM8:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305; >> The code that tells the server to use only those SSL algorithms that I find the most reliable. +``` + +All ciphers for those who want to research one by one: "https://testssl.sh/openssl-iana.mapping.html" + +If you want to check after making the settings: You can use the command "sudo nginx -t". If you do not see an error message, you can apply the settings and restart the service with the command "sudo systemctl restart nginx" or "sudo service nginx restart" + +## Recommended settings + +In addition to the previous settings, we will make some performance improvements, as well as some additional configurations that will enable your site to rank higher in SSL test sites. After that, we will make some improvements to ensure that some headers and resources of your site are not exploited by third party sites, which will be beneficial for your site's user access. + +```text +Titles to be added (changed if any) +ssl_session_cache shared:TLS:2m; >> Code specifying how TLS connections will be distributed among workers (nginx workers) and for how long the connections will be shared + +ssl_buffer_size 4k; >> The code that indicates how many containers the packets will be divided into when responding to SSL requests and sending packets after handshake. A lower value means more packets are sent but less overhead. + +ssl_stapling on; >> Activates the OCSP stapling feature + +ssl_stapling_verify on; Turns on the ability to verify OCSP stapling, including on parent and root servers. + +resolver 1.1.1.1 1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001; >> Enables OCSP stapling verification with Cloudlfare. If you do not use IPV6 or do not want to support it natively, you can delete the IPv6 addresses. + +add_header X-Content-Type-Options "nosniff" always; >> It is the header value that prevents browsers from sniffing to understand MIME contents. + +add_header X-Xss-Protection "1; mode=block" always; >> It is a title that prevents the vulnerability to some extent by allowing users to see a white screen in a possible XSS vulnerability. + +add_header X-Frame-Options "SAMEORIGIN" always; >> It prevents a page of your server from being shown on another page and/or being published one after the other with an i-frame etc. code in any way. Only you can publish a window from your own site within your own site. + +add_header Referrer-Policy "no-referrer-when-downgrade" always; >> When you redirect or link to a site with lower security measures, it does not automatically add a referrer header and it is not clear that traffic is coming from your site. + +add_header Content-Security-Policy "default-src 'self' https: data: 'unsafe-inline' 'unsafe-eval';" always; >> The title that regulates the conditions under which requests that you and other users can call from outside can be called. By default, I trust some sources that come over https. + +add_header Permissions-Policy "camera=(), fullscreen=(self), geolocation=(), microphone=(), payment=()" always; >> It prevents the collection of information on your site with various types of poisoning (cache-poisoning or js-poisoning) by specifying which permissions you will want to the browser or which you will not need at all. +``` + +If you want to check after making the settings: You can use the command "sudo nginx -t". If you do not see an error message, you can apply the settings and restart the service with the command "sudo systemctl restart nginx" or "sudo service nginx restart". + +## Advanced Settings + +First, we'll add a header to your site to indicate that it should only be connected via ssl. In this way, those who have entered your site before and those who already have this title in their browser will not be able to access your site non-SSL even if they want it. Then we will staple the SSL certificates that should be used in HTTP sessions, and we will specify in advance which certificates will need to be connected next to the previous method. In this way, even if you are an authorized top certificate manager or root manager, they will not be able to connect to your site with the certificate signed on your behalf. E-Tugra Root Certificate provider residing in Turkey at the time signed a certificate to *.google.com. If you do a little research, you'll find out when it happened and why (how bad it could cause). Now let's start the final configuration part. + +First, make sure that your site can be accessed over SSL without causing any problems. Then add one of the following headers to the nginx config file as per your request. But beware, only one. + +```text +add_header Strict-Transport-Security "max-age=2592000;" always; >> Header stating that your site can only be accessed over HTTPS for 30 days. (Not including subdomains) + +add_header Strict-Transport-Security "max-age=2592000; includeSubDomains;" always; >> Header stating that your site can only be accessed over HTTPS for 30 days, including subdomains. + +add_header Strict-Transport-Security "max-age=31536000; includeSubDomains;" always; >> Header stating that your site can only be accessed over HTTPS for 1 year, including subdomains. + +add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; >> The header that instructs that your site can only be accessed over HTTPS for 1 year, including subdomains, and that this header is cached by browsers. In addition, new browsers will be aware of this title even if they have never visited your site before. + +add_header Strict-Transport-Security "max-age=0; includeSubDomains"; >> Title for removing HSTS feature and preload list membership completely. +``` + +After adding the header mentioned above, now it's time to staple the hash of the ssl certificate you used to the HTTP session. At this stage we need to extract a hash of your current certificate, hash the top signing authority's certificate, and continue this hashing process until we've completed the entire chain, including the top root certificate authority. For this reason, we run the following commands respectively with a root user or a user with sudo authority. (The lecture was made specifically for Let's Encrypt.) + +```bash +1] cat /etc/letsencrypt/live/YOUR SERVER_NAME/cert.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 >> This command will extract the hash of your site's certificate. Copy the result value somewhere. +2] curl -s https://letsencrypt.org/certs/lets-encrypt-x4-cross-signed.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 >> This command will extract one of the multi-signed certificates of letsencrypt. +3] curl -s https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 >> This command will extract one of the multi-signed certificates of letsencrypt. +4] curl -s https://letsencrypt.org/certs/isrgrootx1.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 >> This command will extract the root (top) certificate of letsencrypt. + +The following value is added to the Nginx config file +5] add_header Public-Key-Pins 'pin-sha256="FIRST_RESULT"; pin-sha256="SECOND_RESULT"; pin-sha256="TIP_END"; pin-sha256="FINISH_RESULT"; max-age=2592000; includeSubDomains' always; >> Allows you to connect to your site for 30 days only with the specified certificate. You can optionally increase the max-age value. Before your certificate validity period is less than 30 days, you must disable the header or obtain a new certificate and add it as the fifth value. + +As a bonus, I'd like to show you another command that will take a long time for your server to execute, but is very useful. +6] openssl dhparam -out /etc/nginx/dhparams.pem 4096 >> This command can take between 15 minutes and 1 hour to execute. + +After the process is finished, you need to add the following command to the nginx config file. +ssl_dhparam /etc/nginx/dhparam.pem; >> The command to change the values ​​to be used during the Diffie-Hellman key exchange algorithm with the secret values ​​we just created, apart from the default values. +``` + +After making the settings, apply the settings with the command "sudo nginx -t" and then, if you do not see an error message, "sudo service nginx restart" and restart the service. Now the connection will be provided with the configuration and conditions you have specified. If you want to see the before/after scoring difference, you can look at the images below or test your own site at "https://www.ssllabs.com/ssltest/index.html". + +BEFORE +![SSL Labs test result](/images/ssl-anlatim/ssl-ilk-hali-ssllabs.png) + +AFTER +![SSL Labs test result](/images/ssl-anlatim/ssl-son-hali-ssllabs.png) + +If you ask why Cipher Strength is not 100%, it is not possible to make 100% at the moment because of the "TLS_AES_128_GCM_SHA256 (0x1301)" that comes automatically with TLS 1.3 and is added even if we don't want it. If you think that I will turn off TLS 1.3, then it will not come, then unfortunately your points are gone from somewhere else. + +# End + +This article was previously published at . In order to create a personal portfolio, I felt the need to republish it on my personal site. diff --git a/content/post/ssl-konfigurasyonu.md b/content/post/ssl-konfigurasyonu.md index cd96feb3..8df20d61 100644 --- a/content/post/ssl-konfigurasyonu.md +++ b/content/post/ssl-konfigurasyonu.md @@ -1,137 +1,137 @@ ---- -title: "Linux Sunucularda SSL güvenliğini arttırma" -date: 2021-10-12 -tags: ["linux", "ssl", "security", "audit"] -author: "Wise" ---- -# Linux Sunucularda SSL güvenliğini artırma - -Bugün sizlere mevcut sunucunuzda eğer bir websitesi ve/veya App serve ediyorsanız mutlaka ihtiyacınız olan SSL bağlantısından ve bununla bağlantılı olarak openssl kütüphanesinden bahsedeceğim. SSL (Secure Socket Layer) ve TLS (Transport Layer Security) sunucunuza bağlanmak isteyen kişileri siteniz ile güvenli şekilde iletişim kurmasına imkan sağlayan bir bağlantı şeklidir. Eskiden SSL v1-v3 arasında değişen sürümler mevcut ve siteler genelde bu SSL sürümlerini kullanırken artık SSL siteler tarafından terk edilmiş ve yerini daha güvenli olan TLS'ye bırakmıştır. Fakat yine de işin anlatımı kısmında ve config dosyalarını düzenlerken halen "ssl" kelimesini kullanmamız gerekecektir. Bunu ufak bir espiri ile de anlatmak gerekirse eğer bir uygulamanın 64 bit versiyonunu indirmek istediğiniz aman "amd_64" olarak neden geçtiğini hiç düşündünüz mü? Çünkü 64 bit'e ilk geçen AMD olduğu için buna bir saygı göstergesi ve/veya alışkanlık olarak amd_64 olarak kaldı bu isimlendirme. Aynı şekilde de şu an TLS kullanıyor olmamıza rağmen isimlendirme ve konfigürasyon parametreleri "SSL" olarak kaldı. - -Daha önceki yazımızda olduğu gibi süreci yine basit, önerilen ve ileri-seviye olarak üç farklı başlık altında anlatacağım. Başlık içerikleri kişisel gerekliliklere göre aşamalı düşünülmüştür. Başlıklar bir biri ile bağlantılı olmasına rağmen istenilen bir aşamada bırakılması sorun oluşturmayacaktır. - -## Basit konfigürasyon - -Öncelikle içinde bulunduğumuz Linux sürümünün paket yöneticisi ile güncellemeleri konsol üzerinden yüklememiz gerekmektedir. - -```bash -Ubuntu için: sudo apt update && sudo apt upgrade -y - -Fedora için: sudo yum update -y - -Arch Linux için: sudo pacman -Syyu -``` - -Güncellemeler yüklendikten sonra ise sunucunuzdaki (Benim olayımda Ubuntu) nginx/apache servisini (ki bu servis dışarıdan gelen web bağlantılarını almanıza yarayan servistir) yapılandırmaya başlıyoruz. Nginx servisinin ayarlarının tutulduğu dosya genel itibariyle "/etc/nginx/nginx.conf" konumunda bulunur. Bunu kendi kullandığımız metin editörlerinden istediğimiz biriyle ama sudo (yani yönetici) yetkilerine sahip bir kullanıcı ile açmamız gerekmektedir. - -Ubuntu üzerinden devam edecek olursak (Tek Ip Tek Sunucu Yapılandırması) - -```bash -sudo nano /etc/nginx/nginx.config # Ayar dosyasını açmaya yarayan komut -``` - -```text -Eklenecek (varsa değiştirilecek) başlıklar -listen 443 ssl http2; >> ipv4 üzerinden 443 portuna gelen istekleri http2 protokolü ile karşılayıp ssl bağlantısı kurmaya yarıyor. - -listen [::]:443 ssl http2; >> ipv6 üzerinden 443 portuna gelen istekleri http2 protokolü ile karşılayıp ssl bağlantısı kurmaya yarıyor. (Eğer ipv6 desteğiniz yok ise veya native olarak desteklemek istemiyorsanız kaldırabilirsiniz) - -server_name SUNUCU_ADINIZ; >> Eğer sunucu adınızı default olarak belirlemek istemiyorsanız bir Server Name Indicator belirleyebilirsiniz. Bu gelen tüm istekleri karşılamak yerine sadece sunucu adınıza gelen istekleri karşılamaya yarar. - -ssl_certificate /etc/letsencrypt/live/SUNUCU_ADINIZ/fullchain.pem; >> Eğer free ssl için Let's Encrypt kullanıyor iseniz default sertifika konumu burasıdır. Aksi halde kendi sertifika dosyanız ile değiştirin. - -ssl_certificate_key /etc/letsencrypt/live/SUNUCU_ADINIZ/privkey.pem; >> Eğer free ssl için Let's Encrypt kullanıyor iseniz default private key konumu burasıdır. Aksi halde kendi private key dosya konumunuz ile değiştirin. - -ssl_protocols TLSv1.3 TLSv1.2; >> Sadece en güncel ve en güvenilir TLS protokollerini kabul etmek için gerekli komut. - -ssl_prefer_server_ciphers on; >> Sunucu ile istemcinin konuşması sırasında "tamam nelerimiz var bakalım" diye konuştuklarını tahmin ettiğim :D kısımda sunucunun sadece kendi seçtiği şifreleme algoritmaları ile bu görüşmeyi devam ettireceğini söylemesine yarayan komut. Kısacası işine gelirse böyle işine gelmezse konuşmuyorum. - -ssl_ecdh_curve secp521r1:secp384r1; >> Ekliptik eğrileri kullanmamız gereken durumlarda hangi eğrileri tercih ettiğimizi bildiren komuttur. - -ssl_ciphers DH-RSA-AES256-SHA:DH-RSA-AES256-SHA256:DHE-RSA-AES256-GCM-SHA384:DH-RSA-AES256-GCM-SHA384:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDH-ECDSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:ECDH-RSA-AES256-SHA:AECDH-AES256-SHA:ECDHE-ECDSA-AES256-SHA384:ECDH-ECDSA-AES256-SHA384:ECDH-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDH-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDH-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-CCM:DHE-RSA-AES256-CCM8:ECDHE-ECDSA-AES256-CCM:ECDHE-ECDSA-AES256-CCM8:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305; >> En güvenilir bulduğum SSL algoritmalarının bir araya getirilerek sadece bunları kullanmasını sunucuya söyleyen kod. -``` - -Tek tek araştırmak isteyenler için tüm cipherlar: "https://testssl.sh/openssl-iana.mapping.html" - -Ayarları yaptıktan sonra kontrol etmek isterseniz: "sudo nginx -t" komutunu kullanabilirsiniz. Eğer bir hata mesajı görmez iseniz "sudo systemctl restart nginx" veya "sudo service nginx restart" komutu ile ayarları uygulayıp servisi baştan başlatabilirsiniz - -## Önerilen ayarlar - -Bir önceki ayarlara ek olarak performans özelinde bazı iyileştirmeler ve bunun yanı sıra sitenizin SSL test sitelerinde üst sıralara çıkmasını sağlayacak bazı ek konfigürasyonlar yapacağız. Bunun ardından ise sitenizin kullanıcı ile erişiminde faydalı olarak bazı başlıkları (header) ve sitenizin kaynaklarının üçüncü kişi siteler tarafından sömürülmemesi için bir takım iyileştirmeler yapacağız. - -```text -Eklenecek (varsa değiştirilecek) başlıklar -ssl_session_cache shared:TLS:2m; >> TLS bağlantılarının işçiler (nginx workers) arasında nasıl dağıtılacağını ve ne kadar süre ile bağlantıların ortak kullanılacağını belirten kod - -ssl_buffer_size 4k; >> SSL isteklerine cevap verirken ve handshake sonrası paket gönderimi yaparken paketlerin kaçlık konteynırlara bölüneceğini belirten kod. Daha düşük bir değer daha çok paket gönderilmesi ama daha az taşma (overhead) anlamına gelir. - -ssl_stapling on; >> OCSP zımbalama özelliğini aktif hale getirir - -ssl_stapling_verify on; OCSP zımbalamanın üst ve kök sunucularda dahil olmak üzere doğrulanması özelliğini açar. - -resolver 1.1.1.1 1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001; >> Cloudlfare ile OCSP zımbalama doğrulamasının yapılmasını sağlar. Eğer IPV6 kullanmıyor veya native olarak desteklemek istemiyorsanız ipv6 adreslerini silebilirsiniz. - -add_header X-Content-Type-Options "nosniff" always; >> Tarayıcıların MIME içeriklerini anlamak için koklama (sniff) yapmasını engeleyen başlık değeridir. - -add_header X-Xss-Protection "1; mode=block" always; >> Olası bir XSS açığında kullanıcıların beyaz ekran görmesini sağlayarak açığı bir nebze de olsa engelleyen bir başlıktır. - -add_header X-Frame-Options "SAMEORIGIN" always; >> Herhangi bir şekilde i-frame vb bir kod ile sunucunuzun bir sayfasının başka bir sayfada gösterilmesini ve/veya alt-alta üst-üste yayımlanmasını engeller. Sadece siz kendi siteniz içerisinde kendi sitenizden bir pencere yayımlayabilirsiniz. - -add_header Referrer-Policy "no-referrer-when-downgrade" always; >> Daha alt güvenlik önlemine sahip bir siteye yönlendirme veya link verdiğinizde otomatik olarak referrer başlığı eklemez ve sitenizden trafik geldiği belli olmaz. - -add_header Content-Security-Policy "default-src 'self' https: data: 'unsafe-inline' 'unsafe-eval';" always; >> Sizin ve diğer kullanıcıların dışarıdan çağırabilecekleri isteklerin hangi koşullar altında çağrılabileceğini düzenleyen başlık. Ben default olarak https üzerinden gelen bazı kaynaklara güveniyorum. - -add_header Permissions-Policy "camera=(), fullscreen=(self), geolocation=(), microphone=(), payment=()" always; >> Tarayıcıya hangi izinleri isteyeceğinizi veya hangilerine hiç ihtiyacınız olmayacağını belirterek çeşitli zehirleme türleri (cache-poisoning veya js-poisoning) ile sizin siteniz üzerinden bilgi toplanmasını engeller. -``` - -Ayarları yaptıktan sonra kontrol etmek isterseniz: "sudo nginx -t" komutunu kullanabilirsiniz. Eğer bir hata mesajı görmez iseniz "sudo systemctl restart nginx" veya "sudo service nginx restart" komutu ile ayarları uygulayıp servisi baştan başlatabilirsiniz. - -## İleri Seviye Ayarlar - -Öncelikle sitenize sadece ssl üzerinden bağlanması gerektiğini gösterecek bir başlık ekleyeceğiz. Bu sayede sizin sitenize daha önce girmiş olanlar ve hali hazırda bu başlığı tarayıcısında mevcut olanlar istese bile sizin sitenize Non-SSL şekilde erişemeyecekler. Ardından ise HTTP oturumlarına kullanılması gereken SSL sertifikalarını zımbalayacağız ve önceki yöntemin yanından hangi sertifikalar ile bağlanması gerekeceğini de önceden belirtmiş olacağız. Bu sayede yetkili bir üst sertifika yöneticisi veya kök yöneticisi olsanız dahi sizin adınıza imzaladığı sertifika ile sizin sitenize bağlanamayacaklar. Zamaında Türkiyede yerleşik E-Tuğra Kök Sertifika sağlayıcısı *.google.com adresine bir sertifika imzaladı. Biraz araştırırsanız hangi dönemde meydana geldiğini ve nedenini (ne kadar kötü sonuçlara neden olabileceğini) fardekersiniz. Şimdi başlayalım son konfigürasyon kısmına. - -Öncelikle sitenizin SSL üzerinden hiçbir soruna neden olmaksızın erişilebiliyor olduğundan emin olun. Ardından nginx konfig dosyasına aşağıdaki başlıklardan isteğinize göre birini ekleyin. Ama dikkat edin sadece bir tanesini. - -```text -add_header Strict-Transport-Security "max-age=2592000;" always; >> Sitenize 30 gün boyunca sadece HTTPS üzerinden erişilebileceğini belirten başlık. (Alt alan adları dahil değil) - -add_header Strict-Transport-Security "max-age=2592000; includeSubDomains;" always; >> Sitenize alt alan adları da dahil olmak üzere 30 gün boyunca sadece HTTPS üzerinden erişilebileceğini belirten başlık. - -add_header Strict-Transport-Security "max-age=31536000; includeSubDomains;" always; >> Sitenize alt alan adları da dahil olmak üzere 1 yıl boyunca sadece HTTPS üzerinden erişilebileceğini belirten başlık. - -add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; >> Sitenize alt alan adları da dahil olmak üzere 1 yıl boyunca sadece HTTPS üzerinden erişilebileceğini ve bu başlığın tarayıcıların önbelleğine alınması talimatını veren başlık. Ayrıca yeni çıkan tarayıcılar sitenize daha önce hiç girmese dahi bu başlıktan haberdar olacaktır. - -add_header Strict-Transport-Security "max-age=0; includeSubDomains"; >> HSTS özelliğini ve preload listesi üyeliğini tamamen kaldırmaya yarayan başlık. -``` - -Yukarıda belirtilen başlığı ekledikten sonra şimdi kullanmış olduğunuz ssl sertifikasının özetinin HTTP oturumuna zımbalanmasına geldi. Bu aşamada mevcut sertifikanızın bir özetini çıkarmamız, üst imzalayan yetkilinin sertifikasının özetini çıkarmamız ve en üst kök sertifika yetkilisi de dahil olmak üzere tüm zinciri tamamlayana kadar bu özet çıkarma sürecini devam ettirmemiz gerekiyor. Bu nedenle root kullanıcısı veya sudo yetkisine sahip bir kullanıcı ile aşağıdaki komutları sırasıyla çalıştırıyoruz. (Anlatım Let's Encrypt özelinde yapılmıştır.) - -```bash -1] cat /etc/letsencrypt/live/SUNUCU_ADINIZ/cert.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 >> Bu komut sizin sitenize ait sertifikanın özetini çıkaracaktır. Sonuç değerini bir yere kopyalayın. -2] curl -s https://letsencrypt.org/certs/lets-encrypt-x4-cross-signed.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 >> Bu komut letsencrypt'e ait çoklu imzalı sertifikalardan bir tanesinin özetini çıkaracaktır. -3] curl -s https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 >> Bu komut letsencrypt'e ait çoklu imzalı sertifikalardan bir tanesinin özetini çıkaracaktır. -4] curl -s https://letsencrypt.org/certs/isrgrootx1.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 >> Bu komut letsencrypt'e ait kök (en üst) sertifikasının özetini çıkaracaktır. - -Nginx config dosyasına aşağıdaki değer eklenir -5] add_header Public-Key-Pins 'pin-sha256="ILK_SONUC"; pin-sha256="IKINCI_SONUC"; pin-sha256="UCUNCU_SONUC"; pin-sha256="DORDUNCU_SONUC"; max-age=2592000; includeSubDomains' always; >> Sitenize 30 gün boyunca sadece belirtilen sertifika ile bağlanılmasına izin verir. Max-age değerini isteğe bağlı olarak artırabilirsiniz. Sertifika geçerlilik süreniz 30 günden daha az kalmadan başlığı devredışı bırakmanız veya yeni sertifika edinmeniz ve beşinci değer olarak onu eklemeniz gerekmektedir. - -Bonus olarak sunucunuzun yapmasının çok uzun süreceği ama faydası çok olan bir komut daha göstermek istiyorum. -6] openssl dhparam -out /etc/nginx/dhparams.pem 4096 >> Bu komutu uygulaması 15dk ile 1 saat arasında sürebilir. - -İşlem bittikten sonra nginx konfig dosyasına aşağıdaki komutu eklemeniz gerekmektedir. -ssl_dhparam /etc/nginx/dhparam.pem; >> Diffie-Hellman anahtar değişim algoritması sırasında kullanılacak değerleri default değerler dışında az önce oluşturduğumuz gizli değerler ile değiştirmeye yarayan komut. -``` - -Ayarları yaptıktan sonra "sudo nginx -t" ve ardından eğer bir hata mesajı görmez iseniz "sudo service nginx restart" komutu ile ayarları uygulayıp servisi baştan başlatın. Artık sizin belirlediğiniz konfigürasyon ve şartlar ile bağlantı sağlanacaktır. Eğer öncesi/sonrası puanlama farkını görmek isterseniz aşağıdaki görsellere bakabilirsiniz veya kendi sitenizi "https://www.ssllabs.com/ssltest/index.html" adresinden test edebilirsiniz. - -İLK HALİ -![SSL Labs test sonucu](/images/ssl-anlatim/ssl-ilk-hali-ssllabs.png) - -SON DURUM -![SSL Labs test sonucu](/images/ssl-anlatim/ssl-son-hali-ssllabs.png) - -Neden Cipher Strength %100 değil derseniz TLS 1.3 ile otomatik gelen ve biz istemesek de eklenen "TLS_AES_128_GCM_SHA256 (0x1301)" yüzünden şu an %100 yapmak mümkün değil. TLS 1.3'ü kapatırım o zaman gelmez diye düşünürseniz o zaman da başka yerden puanınız gidiyor maalesef. - -# Son - -Bu yazı daha önce adresinde yayımlanmıştır. Kişisel portfolyo oluşturmak adına şahsi sitemde yeniden yayımlama ihtiyacı hissettim. +--- +title: "Linux Sunucularda SSL güvenliğini arttırma" +date: 2021-10-12 +tags: ["linux", "ssl", "security", "audit"] +author: "Wise" +--- +# Linux Sunucularda SSL güvenliğini artırma + +Bugün sizlere mevcut sunucunuzda eğer bir websitesi ve/veya App serve ediyorsanız mutlaka ihtiyacınız olan SSL bağlantısından ve bununla bağlantılı olarak openssl kütüphanesinden bahsedeceğim. SSL (Secure Socket Layer) ve TLS (Transport Layer Security) sunucunuza bağlanmak isteyen kişileri siteniz ile güvenli şekilde iletişim kurmasına imkan sağlayan bir bağlantı şeklidir. Eskiden SSL v1-v3 arasında değişen sürümler mevcut ve siteler genelde bu SSL sürümlerini kullanırken artık SSL siteler tarafından terk edilmiş ve yerini daha güvenli olan TLS'ye bırakmıştır. Fakat yine de işin anlatımı kısmında ve config dosyalarını düzenlerken halen "ssl" kelimesini kullanmamız gerekecektir. Bunu ufak bir espiri ile de anlatmak gerekirse eğer bir uygulamanın 64 bit versiyonunu indirmek istediğiniz aman "amd_64" olarak neden geçtiğini hiç düşündünüz mü? Çünkü 64 bit'e ilk geçen AMD olduğu için buna bir saygı göstergesi ve/veya alışkanlık olarak amd_64 olarak kaldı bu isimlendirme. Aynı şekilde de şu an TLS kullanıyor olmamıza rağmen isimlendirme ve konfigürasyon parametreleri "SSL" olarak kaldı. + +Daha önceki yazımızda olduğu gibi süreci yine basit, önerilen ve ileri-seviye olarak üç farklı başlık altında anlatacağım. Başlık içerikleri kişisel gerekliliklere göre aşamalı düşünülmüştür. Başlıklar bir biri ile bağlantılı olmasına rağmen istenilen bir aşamada bırakılması sorun oluşturmayacaktır. + +## Basit konfigürasyon + +Öncelikle içinde bulunduğumuz Linux sürümünün paket yöneticisi ile güncellemeleri konsol üzerinden yüklememiz gerekmektedir. + +```bash +Ubuntu için: sudo apt update && sudo apt upgrade -y + +Fedora için: sudo yum update -y + +Arch Linux için: sudo pacman -Syyu +``` + +Güncellemeler yüklendikten sonra ise sunucunuzdaki (Benim olayımda Ubuntu) nginx/apache servisini (ki bu servis dışarıdan gelen web bağlantılarını almanıza yarayan servistir) yapılandırmaya başlıyoruz. Nginx servisinin ayarlarının tutulduğu dosya genel itibariyle "/etc/nginx/nginx.conf" konumunda bulunur. Bunu kendi kullandığımız metin editörlerinden istediğimiz biriyle ama sudo (yani yönetici) yetkilerine sahip bir kullanıcı ile açmamız gerekmektedir. + +Ubuntu üzerinden devam edecek olursak (Tek Ip Tek Sunucu Yapılandırması) + +```bash +sudo nano /etc/nginx/nginx.config # Ayar dosyasını açmaya yarayan komut +``` + +```text +Eklenecek (varsa değiştirilecek) başlıklar +listen 443 ssl http2; >> ipv4 üzerinden 443 portuna gelen istekleri http2 protokolü ile karşılayıp ssl bağlantısı kurmaya yarıyor. + +listen [::]:443 ssl http2; >> ipv6 üzerinden 443 portuna gelen istekleri http2 protokolü ile karşılayıp ssl bağlantısı kurmaya yarıyor. (Eğer ipv6 desteğiniz yok ise veya native olarak desteklemek istemiyorsanız kaldırabilirsiniz) + +server_name SUNUCU_ADINIZ; >> Eğer sunucu adınızı default olarak belirlemek istemiyorsanız bir Server Name Indicator belirleyebilirsiniz. Bu gelen tüm istekleri karşılamak yerine sadece sunucu adınıza gelen istekleri karşılamaya yarar. + +ssl_certificate /etc/letsencrypt/live/SUNUCU_ADINIZ/fullchain.pem; >> Eğer free ssl için Let's Encrypt kullanıyor iseniz default sertifika konumu burasıdır. Aksi halde kendi sertifika dosyanız ile değiştirin. + +ssl_certificate_key /etc/letsencrypt/live/SUNUCU_ADINIZ/privkey.pem; >> Eğer free ssl için Let's Encrypt kullanıyor iseniz default private key konumu burasıdır. Aksi halde kendi private key dosya konumunuz ile değiştirin. + +ssl_protocols TLSv1.3 TLSv1.2; >> Sadece en güncel ve en güvenilir TLS protokollerini kabul etmek için gerekli komut. + +ssl_prefer_server_ciphers on; >> Sunucu ile istemcinin konuşması sırasında "tamam nelerimiz var bakalım" diye konuştuklarını tahmin ettiğim :D kısımda sunucunun sadece kendi seçtiği şifreleme algoritmaları ile bu görüşmeyi devam ettireceğini söylemesine yarayan komut. Kısacası işine gelirse böyle işine gelmezse konuşmuyorum. + +ssl_ecdh_curve secp521r1:secp384r1; >> Ekliptik eğrileri kullanmamız gereken durumlarda hangi eğrileri tercih ettiğimizi bildiren komuttur. + +ssl_ciphers DH-RSA-AES256-SHA:DH-RSA-AES256-SHA256:DHE-RSA-AES256-GCM-SHA384:DH-RSA-AES256-GCM-SHA384:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDH-ECDSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:ECDH-RSA-AES256-SHA:AECDH-AES256-SHA:ECDHE-ECDSA-AES256-SHA384:ECDH-ECDSA-AES256-SHA384:ECDH-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDH-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDH-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-CCM:DHE-RSA-AES256-CCM8:ECDHE-ECDSA-AES256-CCM:ECDHE-ECDSA-AES256-CCM8:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305; >> En güvenilir bulduğum SSL algoritmalarının bir araya getirilerek sadece bunları kullanmasını sunucuya söyleyen kod. +``` + +Tek tek araştırmak isteyenler için tüm cipherlar: "https://testssl.sh/openssl-iana.mapping.html" + +Ayarları yaptıktan sonra kontrol etmek isterseniz: "sudo nginx -t" komutunu kullanabilirsiniz. Eğer bir hata mesajı görmez iseniz "sudo systemctl restart nginx" veya "sudo service nginx restart" komutu ile ayarları uygulayıp servisi baştan başlatabilirsiniz + +## Önerilen ayarlar + +Bir önceki ayarlara ek olarak performans özelinde bazı iyileştirmeler ve bunun yanı sıra sitenizin SSL test sitelerinde üst sıralara çıkmasını sağlayacak bazı ek konfigürasyonlar yapacağız. Bunun ardından ise sitenizin kullanıcı ile erişiminde faydalı olarak bazı başlıkları (header) ve sitenizin kaynaklarının üçüncü kişi siteler tarafından sömürülmemesi için bir takım iyileştirmeler yapacağız. + +```text +Eklenecek (varsa değiştirilecek) başlıklar +ssl_session_cache shared:TLS:2m; >> TLS bağlantılarının işçiler (nginx workers) arasında nasıl dağıtılacağını ve ne kadar süre ile bağlantıların ortak kullanılacağını belirten kod + +ssl_buffer_size 4k; >> SSL isteklerine cevap verirken ve handshake sonrası paket gönderimi yaparken paketlerin kaçlık konteynırlara bölüneceğini belirten kod. Daha düşük bir değer daha çok paket gönderilmesi ama daha az taşma (overhead) anlamına gelir. + +ssl_stapling on; >> OCSP zımbalama özelliğini aktif hale getirir + +ssl_stapling_verify on; OCSP zımbalamanın üst ve kök sunucularda dahil olmak üzere doğrulanması özelliğini açar. + +resolver 1.1.1.1 1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001; >> Cloudlfare ile OCSP zımbalama doğrulamasının yapılmasını sağlar. Eğer IPV6 kullanmıyor veya native olarak desteklemek istemiyorsanız ipv6 adreslerini silebilirsiniz. + +add_header X-Content-Type-Options "nosniff" always; >> Tarayıcıların MIME içeriklerini anlamak için koklama (sniff) yapmasını engeleyen başlık değeridir. + +add_header X-Xss-Protection "1; mode=block" always; >> Olası bir XSS açığında kullanıcıların beyaz ekran görmesini sağlayarak açığı bir nebze de olsa engelleyen bir başlıktır. + +add_header X-Frame-Options "SAMEORIGIN" always; >> Herhangi bir şekilde i-frame vb bir kod ile sunucunuzun bir sayfasının başka bir sayfada gösterilmesini ve/veya alt-alta üst-üste yayımlanmasını engeller. Sadece siz kendi siteniz içerisinde kendi sitenizden bir pencere yayımlayabilirsiniz. + +add_header Referrer-Policy "no-referrer-when-downgrade" always; >> Daha alt güvenlik önlemine sahip bir siteye yönlendirme veya link verdiğinizde otomatik olarak referrer başlığı eklemez ve sitenizden trafik geldiği belli olmaz. + +add_header Content-Security-Policy "default-src 'self' https: data: 'unsafe-inline' 'unsafe-eval';" always; >> Sizin ve diğer kullanıcıların dışarıdan çağırabilecekleri isteklerin hangi koşullar altında çağrılabileceğini düzenleyen başlık. Ben default olarak https üzerinden gelen bazı kaynaklara güveniyorum. + +add_header Permissions-Policy "camera=(), fullscreen=(self), geolocation=(), microphone=(), payment=()" always; >> Tarayıcıya hangi izinleri isteyeceğinizi veya hangilerine hiç ihtiyacınız olmayacağını belirterek çeşitli zehirleme türleri (cache-poisoning veya js-poisoning) ile sizin siteniz üzerinden bilgi toplanmasını engeller. +``` + +Ayarları yaptıktan sonra kontrol etmek isterseniz: "sudo nginx -t" komutunu kullanabilirsiniz. Eğer bir hata mesajı görmez iseniz "sudo systemctl restart nginx" veya "sudo service nginx restart" komutu ile ayarları uygulayıp servisi baştan başlatabilirsiniz. + +## İleri Seviye Ayarlar + +Öncelikle sitenize sadece ssl üzerinden bağlanması gerektiğini gösterecek bir başlık ekleyeceğiz. Bu sayede sizin sitenize daha önce girmiş olanlar ve hali hazırda bu başlığı tarayıcısında mevcut olanlar istese bile sizin sitenize Non-SSL şekilde erişemeyecekler. Ardından ise HTTP oturumlarına kullanılması gereken SSL sertifikalarını zımbalayacağız ve önceki yöntemin yanından hangi sertifikalar ile bağlanması gerekeceğini de önceden belirtmiş olacağız. Bu sayede yetkili bir üst sertifika yöneticisi veya kök yöneticisi olsanız dahi sizin adınıza imzaladığı sertifika ile sizin sitenize bağlanamayacaklar. Zamaında Türkiyede yerleşik E-Tuğra Kök Sertifika sağlayıcısı *.google.com adresine bir sertifika imzaladı. Biraz araştırırsanız hangi dönemde meydana geldiğini ve nedenini (ne kadar kötü sonuçlara neden olabileceğini) fardekersiniz. Şimdi başlayalım son konfigürasyon kısmına. + +Öncelikle sitenizin SSL üzerinden hiçbir soruna neden olmaksızın erişilebiliyor olduğundan emin olun. Ardından nginx konfig dosyasına aşağıdaki başlıklardan isteğinize göre birini ekleyin. Ama dikkat edin sadece bir tanesini. + +```text +add_header Strict-Transport-Security "max-age=2592000;" always; >> Sitenize 30 gün boyunca sadece HTTPS üzerinden erişilebileceğini belirten başlık. (Alt alan adları dahil değil) + +add_header Strict-Transport-Security "max-age=2592000; includeSubDomains;" always; >> Sitenize alt alan adları da dahil olmak üzere 30 gün boyunca sadece HTTPS üzerinden erişilebileceğini belirten başlık. + +add_header Strict-Transport-Security "max-age=31536000; includeSubDomains;" always; >> Sitenize alt alan adları da dahil olmak üzere 1 yıl boyunca sadece HTTPS üzerinden erişilebileceğini belirten başlık. + +add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; >> Sitenize alt alan adları da dahil olmak üzere 1 yıl boyunca sadece HTTPS üzerinden erişilebileceğini ve bu başlığın tarayıcıların önbelleğine alınması talimatını veren başlık. Ayrıca yeni çıkan tarayıcılar sitenize daha önce hiç girmese dahi bu başlıktan haberdar olacaktır. + +add_header Strict-Transport-Security "max-age=0; includeSubDomains"; >> HSTS özelliğini ve preload listesi üyeliğini tamamen kaldırmaya yarayan başlık. +``` + +Yukarıda belirtilen başlığı ekledikten sonra şimdi kullanmış olduğunuz ssl sertifikasının özetinin HTTP oturumuna zımbalanmasına geldi. Bu aşamada mevcut sertifikanızın bir özetini çıkarmamız, üst imzalayan yetkilinin sertifikasının özetini çıkarmamız ve en üst kök sertifika yetkilisi de dahil olmak üzere tüm zinciri tamamlayana kadar bu özet çıkarma sürecini devam ettirmemiz gerekiyor. Bu nedenle root kullanıcısı veya sudo yetkisine sahip bir kullanıcı ile aşağıdaki komutları sırasıyla çalıştırıyoruz. (Anlatım Let's Encrypt özelinde yapılmıştır.) + +```bash +1] cat /etc/letsencrypt/live/SUNUCU_ADINIZ/cert.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 >> Bu komut sizin sitenize ait sertifikanın özetini çıkaracaktır. Sonuç değerini bir yere kopyalayın. +2] curl -s https://letsencrypt.org/certs/lets-encrypt-x4-cross-signed.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 >> Bu komut letsencrypt'e ait çoklu imzalı sertifikalardan bir tanesinin özetini çıkaracaktır. +3] curl -s https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 >> Bu komut letsencrypt'e ait çoklu imzalı sertifikalardan bir tanesinin özetini çıkaracaktır. +4] curl -s https://letsencrypt.org/certs/isrgrootx1.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 >> Bu komut letsencrypt'e ait kök (en üst) sertifikasının özetini çıkaracaktır. + +Nginx config dosyasına aşağıdaki değer eklenir +5] add_header Public-Key-Pins 'pin-sha256="ILK_SONUC"; pin-sha256="IKINCI_SONUC"; pin-sha256="UCUNCU_SONUC"; pin-sha256="DORDUNCU_SONUC"; max-age=2592000; includeSubDomains' always; >> Sitenize 30 gün boyunca sadece belirtilen sertifika ile bağlanılmasına izin verir. Max-age değerini isteğe bağlı olarak artırabilirsiniz. Sertifika geçerlilik süreniz 30 günden daha az kalmadan başlığı devredışı bırakmanız veya yeni sertifika edinmeniz ve beşinci değer olarak onu eklemeniz gerekmektedir. + +Bonus olarak sunucunuzun yapmasının çok uzun süreceği ama faydası çok olan bir komut daha göstermek istiyorum. +6] openssl dhparam -out /etc/nginx/dhparams.pem 4096 >> Bu komutu uygulaması 15dk ile 1 saat arasında sürebilir. + +İşlem bittikten sonra nginx konfig dosyasına aşağıdaki komutu eklemeniz gerekmektedir. +ssl_dhparam /etc/nginx/dhparam.pem; >> Diffie-Hellman anahtar değişim algoritması sırasında kullanılacak değerleri default değerler dışında az önce oluşturduğumuz gizli değerler ile değiştirmeye yarayan komut. +``` + +Ayarları yaptıktan sonra "sudo nginx -t" ve ardından eğer bir hata mesajı görmez iseniz "sudo service nginx restart" komutu ile ayarları uygulayıp servisi baştan başlatın. Artık sizin belirlediğiniz konfigürasyon ve şartlar ile bağlantı sağlanacaktır. Eğer öncesi/sonrası puanlama farkını görmek isterseniz aşağıdaki görsellere bakabilirsiniz veya kendi sitenizi "https://www.ssllabs.com/ssltest/index.html" adresinden test edebilirsiniz. + +İLK HALİ +![SSL Labs test sonucu](/images/ssl-anlatim/ssl-ilk-hali-ssllabs.png) + +SON DURUM +![SSL Labs test sonucu](/images/ssl-anlatim/ssl-son-hali-ssllabs.png) + +Neden Cipher Strength %100 değil derseniz TLS 1.3 ile otomatik gelen ve biz istemesek de eklenen "TLS_AES_128_GCM_SHA256 (0x1301)" yüzünden şu an %100 yapmak mümkün değil. TLS 1.3'ü kapatırım o zaman gelmez diye düşünürseniz o zaman da başka yerden puanınız gidiyor maalesef. + +# Son + +Bu yazı daha önce adresinde yayımlanmıştır. Kişisel portfolyo oluşturmak adına şahsi sitemde yeniden yayımlama ihtiyacı hissettim. diff --git a/layouts/shortcodes/img.html.BACKUP b/layouts/shortcodes/img.html.BACKUP index 99a69e05..37e16f21 100644 --- a/layouts/shortcodes/img.html.BACKUP +++ b/layouts/shortcodes/img.html.BACKUP @@ -1,25 +1,25 @@ -{{ $img := resources.GetMatch (.Get "src") }} - -{{- $ws := uniq (slice 240 300 360 420 480 600 768 800 960 1024 1080 1200 1366 1440 1920 $img.Width) -}} - -{{- $srcset := slice -}} -{{ range sort $ws }} - {{ if (le . $img.Width) }} - {{ $w := printf "%dx webp q50" . }} - {{ $url := printf "%s %dw" (($img.Resize $w).RelPermalink | absURL | safeURL) . }} - {{ $srcset = $srcset | append $url }} - {{ end }} -{{ end }} - -{{ $set := delimit $srcset "," }} - - -{{ $alt := .Get "alt" }} -{{ $title := cond (not (.Get "title")) $alt (.Get "title") }} - -
-
- {{ $alt | safeHTML }} -
-
{{$alt | safeHTML }}
-
+{{ $img := resources.GetMatch (.Get "src") }} + +{{- $ws := uniq (slice 240 300 360 420 480 600 768 800 960 1024 1080 1200 1366 1440 1920 $img.Width) -}} + +{{- $srcset := slice -}} +{{ range sort $ws }} + {{ if (le . $img.Width) }} + {{ $w := printf "%dx webp q50" . }} + {{ $url := printf "%s %dw" (($img.Resize $w).RelPermalink | absURL | safeURL) . }} + {{ $srcset = $srcset | append $url }} + {{ end }} +{{ end }} + +{{ $set := delimit $srcset "," }} + + +{{ $alt := .Get "alt" }} +{{ $title := cond (not (.Get "title")) $alt (.Get "title") }} + +
+
+ {{ $alt | safeHTML }} +
+
{{$alt | safeHTML }}
+
diff --git a/static/images/fotograf-compress-magick/giris1.avif b/static/images/fotograf-compress-magick/giris1.avif new file mode 100644 index 0000000000000000000000000000000000000000..359a6a00e7a33910cf02ffec93b1cfaba95f37c1 GIT binary patch literal 3481 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 literal 0 HcmV?d00001 diff --git a/static/images/fotograf-compress-magick/giris1.png b/static/images/fotograf-compress-magick/giris1.png new file mode 100644 index 0000000000000000000000000000000000000000..8517a102fec4fbfdffc9ba3d692028a6e24634d8 GIT binary patch literal 21179 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 literal 0 HcmV?d00001 diff --git a/static/images/fotograf-compress-magick/giris1.webp b/static/images/fotograf-compress-magick/giris1.webp new file mode 100644 index 0000000000000000000000000000000000000000..6cd35c6a7143ffba5dd299704a785e8fba771c8a GIT binary patch literal 8754 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 a4Ili9`C5(7%@~DFMy;u;r&0*t2>vfAPKx>f literal 0 HcmV?d00001 diff --git a/static/images/fotograf-compress-magick/giris2.webp b/static/images/fotograf-compress-magick/giris2.webp new file mode 100644 index 0000000000000000000000000000000000000000..0dbe7bcbcebbd332ac169c13e59a52aed7a1dff0 GIT binary patch literal 19342 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 zXj;!VCAkf6?K4+DtxEF1000000000000000000000000000000000000000000000 G00027dmN0001iiIcmX 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 XMK3D!DFzC!{-9dmi54l5S)_<~4DYWg literal 0 HcmV?d00001 diff --git a/static/images/fotograf-compress-magick/mid1.png b/static/images/fotograf-compress-magick/mid1.png new file mode 100644 index 0000000000000000000000000000000000000000..1bd40bd040b26d29b33f2aff755336c770cf5791 GIT binary patch literal 111943 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

=W=$-5i__P@dC-&0 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 z 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 literal 0 HcmV?d00001 diff --git a/static/images/fotograf-compress-magick/mid2.avif b/static/images/fotograf-compress-magick/mid2.avif new file mode 100644 index 0000000000000000000000000000000000000000..2b0090a8da712f77ff22d7eccd3e90a7eecea9c9 GIT binary patch literal 5603 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 XOx(365p{kL_;*+7p5h02i)a4_{K-En literal 0 HcmV?d00001 diff --git a/static/images/fotograf-compress-magick/mid2.webp b/static/images/fotograf-compress-magick/mid2.webp new file mode 100644 index 0000000000000000000000000000000000000000..f6d82d8132a4cc96d27e1a0b0cc3b98b4535e6d5 GIT binary patch literal 17928 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 literal 0 HcmV?d00001 diff --git a/themes/hugo-PaperMod b/themes/hugo-PaperMod index aa7905ea..9ea3bb0e 160000 --- a/themes/hugo-PaperMod +++ b/themes/hugo-PaperMod @@ -1 +1 @@ -Subproject commit aa7905eaca435f15aa9cb0efc4b15459049f58c5 +Subproject commit 9ea3bb0e1f3aa06ed7715e73b5fabb36323f7267