it-swarm-id.com

Mencoba membuat situs berbasis Django hanya menggunakan HTTPS, tidak yakin apakah itu aman?

EFF merekomendasikan menggunakan HTTPS di mana-mana di situs Anda, dan saya yakin situs ini akan setuju. Ketika saya mengajukan pertanyaan tentang menggunakan Django untuk mengimplementasikan HTTPS pada halaman login saya, itu sudah pasti tanggapan yang saya dapatkan :)

Jadi saya mencoba melakukan hal itu. Saya memiliki pengaturan Django/nginx yang saya coba konfigurasikan hanya untuk HTTPS - ini berfungsi, tetapi ada masalah. Lebih penting lagi, saya yakin jika itu benar-benar aman , meskipun melihat https awalan.

Saya telah mengkonfigurasi nginx untuk mengalihkan semua halaman http ke https, dan bagian itu berfungsi. Namun ... Katakanlah saya punya halaman, https://mysite.com/search/, dengan form/tombol pencarian di atasnya. Saya mengklik tombol, Django memproses formulir, dan melakukan redirect ke halaman hasil , yaitu http://mysite.com/search/results?term="foo".

URL ini dikirim ke browser, yang mengirimkannya kembali ke server nginx, yang melakukan redirect permanen ke https- diawali versi halaman. (Setidaknya saya berpikir itulah yang terjadi - tentu saja IE memperingatkan saya bahwa saya akan pergi ke halaman yang tidak aman , lalu kembali ke halaman aman :)

Tetapi apakah ini benar-benar aman? Atau, setidaknya keamanan sebanyak yang dimiliki oleh situs standar HTTPS saja? Apakah fakta bahwa Django mentransmisikan URL awalan http, seseorang yang membahayakan keamanan? Ya, sejauh yang dapat saya katakan, hanya laman yang memiliki awalan https-yang dapat dijawab, tetapi hanya tidak 't merasa benar :) Keamanannya funky, karena situs ini dapat membuktikannya, dan saya khawatir ada sesuatu yang saya lewatkan.

63
John C

Amankan cookie Anda

Di settings.py masukkan baris

SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

dan cookie hanya akan dikirim melalui koneksi HTTPS. Selain itu, Anda mungkin juga menginginkan SESSION_EXPIRE_AT_BROWSER_CLOSE=True. Perhatikan jika Anda menggunakan versi yang lebih lama dari Django (kurang dari 1.4), tidak ada pengaturan untuk cookie CSRF yang aman. Sebagai perbaikan cepat, Anda hanya dapat membuat cookie CSRF aman ketika cookie sesi aman (SESSION_COOKIE_SECURE=True), dengan mengedit Django/middleware/csrf.py:

class CsrfViewMiddleware(object):
   ...
   def process_response(self, request, response):
       ...
       response.set_cookie(settings.CSRF_COOKIE_NAME,
            request.META["CSRF_COOKIE"], max_age = 60 * 60 * 24 * 7 * 52,
            domain=settings.CSRF_COOKIE_DOMAIN,
            secure=settings.SESSION_COOKIE_SECURE or None)

Permintaan HTTP langsung ke HTTPS di server web

Selanjutnya Anda ingin aturan penulisan ulang yang mengalihkan permintaan http ke https, mis., Di nginx

server {
   listen 80;
   rewrite ^(.*) https://$Host$1 permanent;
}

Fungsi Django reverse dan tag templat url hanya mengembalikan tautan relatif; jadi jika Anda berada di halaman https, tautan Anda akan membuat Anda di situs https.

Setel HTTPS variabel lingkungan OS ke aktif

Akhirnya, (dan tanggapan awal saya mengecualikan ini), Anda perlu mengaktifkan variabel lingkungan OS HTTPS hingga 'on' Jadi Django akan menambahkan https ke tautan yang dibuat sepenuhnya) (mis. suka dengan HttpRedirectRequests). Jika Anda menggunakan mod_wsgi, Anda dapat menambahkan baris:

os.environ['HTTPS'] = "on"

ke skrip wsgi Anda . Jika Anda menggunakan uwsgi, Anda dapat menambahkan variabel lingkungan dengan saklar baris perintah --env HTTPS=on Atau dengan menambahkan baris env = HTTPS=on Ke file uwsgi .ini Anda. Sebagai pilihan terakhir jika tidak ada yang berfungsi, Anda dapat mengedit file pengaturan agar memiliki baris import os Dan os.environ['HTTPS'] = "on", Yang juga harus berfungsi.

Jika Anda menggunakan wsgi, Anda mungkin ingin juga mengatur variabel lingkungan wsgi.url_scheme Ke 'https' Dengan menambahkan ini ke settings.py Anda:

os.environ['wsgi.url_scheme'] = 'https'

Saran wsgi berasal dari komentar Vijayendra Bapte .

Anda dapat melihat perlunya variabel lingkungan ini dengan membaca Django/http/__init__.py:

def build_absolute_uri(self, location=None):
    """
    Builds an absolute URI from the location and the variables available in
    this request. If no location is specified, the absolute URI is built on
    ``request.get_full_path()``.
    """
    if not location:
        location = self.get_full_path()
    if not absolute_http_url_re.match(location):
        current_uri = '%s://%s%s' % (self.is_secure() and 'https' or 'http',
                                     self.get_Host(), self.path)
        location = urljoin(current_uri, location)
    return iri_to_uri(location)

def is_secure(self):
    return os.environ.get("HTTPS") == "on"

Hal-hal Server Web Tambahan:

Ambil saran orang itu dan nyalakan header HSTS di server web Anda dengan menambahkan baris ke nginx:

add_header Strict-Transport-Security max-age=31536000;

Ini memberi tahu browser web Anda bahwa situs web Anda selama 10 tahun mendatang hanya akan menggunakan HTTPS. Jika ada serangan Man-in-the-middle pada setiap kunjungan di masa depan dari browser yang sama (misalnya, Anda masuk ke router jahat di warung kopi yang mengarahkan Anda ke versi HTTP halaman), browser Anda akan mengingat seharusnya hanya HTTPS dan mencegah Anda secara tidak sengaja menyerahkan informasi Anda. Tapi hati-hati tentang ini, Anda tidak dapat berubah pikiran dan kemudian memutuskan bagian dari domain Anda akan dilayani melalui HTTP (sampai 10 tahun berlalu sejak Anda menghapus baris ini). Jadi rencanakan ke depan; mis., jika Anda yakin aplikasi Anda akan segera tumbuh dalam popularitas dan Anda harus menggunakan CDN besar yang tidak menangani HTTPS dengan baik dengan harga yang Anda mampu, Anda mungkin memiliki masalah.

Pastikan juga Anda menonaktifkan protokol yang lemah. Kirim domain Anda ke Uji SSL untuk memeriksa kemungkinan masalah (kunci terlalu pendek, tidak menggunakan TLSv1.2, menggunakan protokol yang rusak, dll.). E.g., dalam nginx saya menggunakan:

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";
67
dr jimbob

Mengarahkan ulang dari http: // ke https: // halaman yang sesuai adalah pendekatan yang salah. Konfigurasikan nginx untuk mengalihkan port 80 ke https: //domainanda.ext/

server {
       listen 80;
       rewrite ^/? https://$Host/ permanent;
 }

atau serupa (periksa manual nginx berikutnya di dekat Anda) dan jangan menjalankan aplikasi Anda sama sekali pada port 80 (http). Jadi, permintaan lain pada port 80 menyelesaikan ke 404 atau serupa (sesuaikan, dengan mengatakan bahwa aplikasi Anda sekarang aman dan hanya berjalan di https dengan tautan yang menunjuk ke https: // domainAnda.ext/ ) . Kemudian jalankan aplikasi Anda hanya di dengarkan port 443 (https). Menggunakan jalur relatif dalam kode Anda sekarang aman, karena semuanya menyelesaikan ke https penuh: // jalur dan Anda menghindari memantul http ke https!

3
esskar

anda juga harus mengirim HSTS-Header dari nginx, menunjukkan kepada klien (browser) mereka hanya akan menggunakan HTTPS

add_header Strict-Transport-Security max-age=31536000;

Pengaturan umum akan meminta Anda meneruskan lalu lintas https dari server web Anda (mis. Nginx) ke server http lokal yang menjalankan aplikasi Django.

Dalam hal ini akan lebih mudah untuk menggunakan SECURE_PROXY_SSL_HEADER pengaturan (tersedia sejak Django 1.4.)

https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-SECURE_PROXY_SSL_HEADER

3
Sebastian

Saya pikir apa yang Anda cari adalah middleware Django yang akan menulis ulang http ke https. Sesuatu yang mirip dengan apa yang dibahas di ini pertanyaan pada SO , di mana satu jawaban menunjuk ke middleware ini . Anda mungkin harus menulis middleware Anda sendiri, tetapi harus langsung (pertanyaan yang terfokus pada SO akan mengarahkan Anda ke arah yang benar jika Anda membutuhkan bantuan untuk memulai.)

2
bstpierre

Dalam kebanyakan kasus, Anda dapat mengatur Apache atau sesuatu untuk dialihkan ke https, seperti dijelaskan dalam jawaban yang diterima. Dan jika Anda bisa, itu akan lebih baik, untuk kinerja dan untuk file yang disajikan di luar Django.

Tetapi jika Anda tidak bisa, atau ingin melakukan debugging, maka saya ingin menunjukkan bahwa Django baru-baru ini (1,8) memperkenalkan SecurityMiddleware yang memiliki https-redirects sebagai salah satunya beberapa fungsi.

Info lebih lanjut tersedia di dokumentasi . Pada dasarnya, tambahkan Django.middleware.security.SecurityMiddleware dan atur SECURE_SSL_REDIRECT = True.

(Header yang disebutkan oleh jawaban yang diterima juga dapat diatur oleh middleware ini.)

2
Mark

Anda perlu mengkonfigurasi Django untuk menghasilkan keduanya

  1. https://domain/path tautan dengan https: skema,
  2. //domain/path tautan tanpa skema (browser akan mengartikan ini sebagai skema yang sama dengan halaman yang dibuka saat itu), atau
  3. /path tautan tanpa skema atau domain (browser akan menafsirkan ini memiliki skema dan domain yang sama dengan halaman yang saat ini ditunjuk).
1
yfeldblum