it-swarm-vi.com

Cố gắng tạo một trang web dựa trên Django chỉ sử dụng HTTPS, không chắc nó có an toàn không?

EFF khuyến nghị sử dụng HTTPS ở mọi nơi trên trang web của bạn và tôi chắc chắn trang web này sẽ đồng ý. Khi tôi hỏi một câu hỏi về việc sử dụng Django để triển khai HTTPS trên trang đăng nhập của tôi, đó chắc chắn là câu trả lời tôi nhận được :)

Vì vậy, tôi đang cố gắng để làm điều đó. Tôi có một thiết lập Django/nginx mà tôi đang cố gắng định cấu hình cho chỉ HTTPS - nó hoạt động tốt, nhưng có vấn đề. Quan trọng hơn, tôi chắc chắn nếu nó thực sự an toàn , mặc dù nhìn thấy https tiếp đầu ngữ.

Tôi đã định cấu hình nginx để chuyển hướng tất cả các trang http sang https và phần đó hoạt động. Tuy nhiên ... Nói rằng tôi có một trang, https://mysite.com/search/, với một hình thức/nút tìm kiếm trên đó. Tôi nhấp vào nút, Django xử lý biểu mẫu và thực hiện chuyển hướng đến trang kết quả , đó là http://mysite.com/search/results?term="foo".

URL này được gửi tới trình duyệt, nó sẽ gửi lại cho máy chủ nginx, chuyển hướng vĩnh viễn đến https- có tiền tố phiên bản của trang. (Ít nhất là tôi nghĩ đó là những gì đang xảy ra - chắc chắn IE cảnh báo tôi rằng tôi sẽ đến một trang không an toàn và sau đó quay lại trang an toàn :)

Nhưng điều này có thực sự an toàn không? Hoặc, ít nhất là bảo mật nhiều như một trang web chỉ HTTPS tiêu chuẩn sẽ có? Có phải thực tế là Django truyền URL tiền tố http, ai đó đang xâm phạm bảo mật? Có, theo như tôi có thể nói, chỉ những trang có tiền tố https mới được trả lời, nhưng nó chỉ không 't cảm thấy đúng :) Bảo mật rất thú vị, vì trang web này có thể chứng thực và tôi lo lắng có điều gì đó tôi đang thiếu.

63
John C

Bảo mật cookie của bạn

Trong settings.py đặt các dòng

SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

và cookie sẽ chỉ được gửi qua các kết nối HTTPS. Ngoài ra, bạn có thể cũng muốn SESSION_EXPIRE_AT_BROWSER_CLOSE=True. Lưu ý nếu bạn đang sử dụng các phiên bản cũ hơn Django (dưới 1,4), không có cài đặt nào cho cookie CSRF an toàn. Để khắc phục nhanh, bạn có thể bảo mật cookie CSRF khi cookie phiên được bảo mật (SESSION_COOKIE_SECURE=True), bằng cách chỉnh sửa 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)

Yêu cầu HTTP trực tiếp đến HTTPS trong máy chủ web

Tiếp theo, bạn muốn một quy tắc viết lại chuyển hướng các yêu cầu http đến https, ví dụ: trong nginx

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

Các thẻ chức năng và url của Django reverse chỉ trả về các liên kết tương đối; vì vậy nếu bạn ở trên trang https, các liên kết của bạn sẽ giữ bạn trên trang https.

Đặt HTTPS biến môi trường thành bật

Cuối cùng, (và phản hồi ban đầu của tôi đã loại trừ điều này), bạn cần kích hoạt biến môi trường HĐH HTTPS thành 'on' Vì vậy Django sẽ trả trước https cho các liên kết được tạo hoàn toàn ( ví dụ: như với HttpRedirectRequests). Nếu bạn đang sử dụng mod_wsgi, bạn có thể thêm dòng:

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

vào tập lệnh wsgi . Nếu bạn đang sử dụng uwsgi, bạn có thể thêm một biến môi trường bằng cách chuyển đổi dòng lệnh --env HTTPS=on Hoặc bằng cách thêm dòng env = HTTPS=on Vào tệp uwsgi .ini. Như một phương sách cuối cùng nếu không có gì khác hoạt động, bạn có thể chỉnh sửa tệp cài đặt của mình để có các dòng import osos.environ['HTTPS'] = "on", Cũng sẽ hoạt động.

Nếu bạn đang sử dụng wsgi, bạn có thể muốn đặt thêm biến môi trường wsgi.url_scheme Thành 'https' Bằng cách thêm giá trị này vào settings.py:

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

Lời khuyên của wsgi nhờ bình luận của Vijayendra Bapte .

Bạn có thể thấy sự cần thiết của biến môi trường này bằng cách đọc 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"

Những điều máy chủ web bổ sung:

Lấy lời khuyên của anh chàng đó và bật tiêu đề HSTS trong máy chủ web của bạn bằng cách thêm một dòng vào nginx:

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

Điều này cho trình duyệt web của bạn biết rằng trang web của bạn trong 10 năm tới sẽ chỉ sử dụng HTTPS. Nếu có bất kỳ cuộc tấn công trung gian nào vào bất kỳ lượt truy cập nào trong tương lai từ cùng một trình duyệt (ví dụ: bạn đăng nhập vào bộ định tuyến độc hại trong quán cà phê chuyển hướng bạn đến phiên bản HTTP của trang), trình duyệt của bạn sẽ nhớ nó chỉ được coi là HTTPS và ngăn bạn vô tình từ bỏ thông tin của bạn. Nhưng hãy cẩn thận về điều này, bạn không thể thay đổi ý định và sau đó quyết định một phần tên miền của bạn sẽ được phục vụ qua HTTP (cho đến khi 10 năm trôi qua kể từ khi bạn xóa dòng này). Vì vậy, lên kế hoạch trước; ví dụ: nếu bạn tin rằng ứng dụng của bạn có thể sớm trở nên phổ biến và bạn sẽ cần phải có một CDN lớn không xử lý tốt HTTPS với mức giá bạn có thể chi trả, bạn có thể gặp vấn đề.

Cũng đảm bảo rằng bạn vô hiệu hóa các giao thức yếu. Gửi tên miền của bạn tới Kiểm tra SSL để kiểm tra các sự cố tiềm ẩn (khóa quá ngắn, không sử dụng TLSv1.2, sử dụng giao thức bị hỏng, v.v.). Ví dụ: trong nginx tôi sử dụng:

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

Chuyển hướng từ bất kỳ http: // đến trang https: // tương ứng là cách tiếp cận sai. Định cấu hình nginx để chuyển hướng cổng 80 sang https: //yourdomain.ext/

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

hoặc tương tự (kiểm tra hướng dẫn sử dụng nginx tiếp theo gần bạn) và hoàn toàn không chạy ứng dụng của bạn trên cổng 80 (http). Vì vậy, các yêu cầu khác trên cổng 80 giải quyết 404 hoặc tương tự (tùy chỉnh nó, nói rằng ứng dụng của bạn hiện an toàn và chỉ chạy trên https với liên kết trỏ đến https: //yourdomain.ext/ ) . Sau đó, chỉ chạy ứng dụng của bạn trên cổng nghe 443 (https). Sử dụng các đường dẫn tương đối trong mã của bạn hiện đã được bảo mật, vì tất cả chúng đều phân giải thành đường dẫn https: // đầy đủ và bạn tránh được việc chuyển từ http sang https!

3
esskar

bạn cũng nên gửi HSTS-Header từ nginx, cho biết khách hàng (trình duyệt) họ sẽ chỉ sử dụng HTTPS

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

Một thiết lập chung sẽ giúp bạn chuyển tiếp lưu lượng https từ máy chủ web của bạn (tức là Nginx) đến máy chủ http cục bộ chạy ứng dụng Django.

Trong trường hợp này, việc sử dụng cài đặt SECURE_PROXY_SSL_HEADER Sẽ dễ dàng hơn (có sẵn kể từ Django 1.4.)

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

3
Sebastian

Tôi nghĩ những gì bạn đang tìm kiếm là một Django phần mềm trung gian sẽ viết lại http thành https. Một cái gì đó tương tự như những gì được đề cập trong cái này câu hỏi về SO , trong đó một câu trả lời chỉ ra phần mềm trung gian này . Có lẽ bạn sẽ phải viết phần mềm trung gian của riêng mình, nhưng nó nên đơn giản. (Một câu hỏi tập trung tốt vào SO sẽ giúp bạn đi đúng hướng nếu bạn cần trợ giúp để bắt đầu.)

2
bstpierre

Trong hầu hết các trường hợp, bạn có thể đặt Apache hoặc thứ gì đó để chuyển hướng sang https, như được mô tả trong câu trả lời được chấp nhận. Và nếu bạn có thể, điều đó sẽ tốt hơn, cho hiệu suất và cho các tệp được phục vụ bên ngoài Django.

Nhưng nếu bạn không thể hoặc muốn gỡ lỗi, thì tôi muốn chỉ ra rằng Django gần đây (1.8) đã giới thiệu một SecurityMiddleware có chuyển hướng https là một trong số đó một số chức năng.

Thêm thông tin có sẵn trong tài liệ . Về cơ bản, thêm Django.middleware.security.SecurityMiddleware và thiết lập SECURE_SSL_REDIRECT = True.

(Tiêu đề được đề cập bởi câu trả lời được chấp nhận cũng có thể được đặt bởi phần mềm trung gian này.)

2
Mark

Bạn cần định cấu hình Django để tạo một trong hai

  1. https://domain/path liên kết với https: kế hoạch,
  2. //domain/path liên kết không có lược đồ (trình duyệt sẽ hiểu các liên kết này có cùng lược đồ với trang hiện đang mở) hoặc
  3. /path liên kết không có lược đồ hoặc tên miền (trình duyệt sẽ diễn giải những thứ này có cùng sơ đồ và tên miền như trang hiện tại được trỏ đến).
1
yfeldblum