2009-09-02 68 views
13

Tôi đang sử dụng Python 2.5 trên Linux, trong nhiều quy trình FCGI song song. Tôi sử dụngrandom.choice không ngẫu nhiên

chars = string.ascii_letters + string.digits 
    cookie = ''.join([random.choice(chars) for x in range(32)]) 

để tạo các cookie riêng biệt. Giả sử RNG được tạo hạt giống từ/dev/urandom, và rằng chuỗi các số ngẫu nhiên xuất phát từ twister Mersenne, tôi hy vọng rằng thực tế là không có va chạm.

Tuy nhiên, tôi thấy các va chạm thường xuyên, mặc dù chỉ một số ít (< 100) người dùng đã đăng nhập bất kỳ lúc nào.

Tại sao các số ngẫu nhiên không ngẫu nhiên hơn?

+4

Ký tự là gì? Nếu bạn có một nhân vật duy nhất trong đó bạn sẽ luôn luôn có va chạm (để minh họa cho điểm) –

+0

độ dài của danh sách ký tự là gì? –

+0

Tôi đã thêm định nghĩa của tôi về ký tự bây giờ - nó không phải là một nhân vật duy nhất, nhưng có 62 lựa chọn. –

Trả lời

12

Không nên tạo bản sao.

import random 
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 
def gen(): 
    return ''.join([random.choice(chars) for x in range(32)]) 

test = [gen() for i in range(100000)] 
print len(test), len(set(test)) # 100000 100000 

Cơ hội trùng lặp có ý nghĩa với ký tự = "ab"; 126 bản sao trong 1000000 lần lặp. Đó là không tồn tại với 62.

Điều đó nói rằng, đây không phải là cách hay để tạo cookie, vì cookie phiên cần phải không thể dự đoán được, để tránh các cuộc tấn công liên quan đến việc ăn cắp cookie phiên của người khác. Misterenne Twister không được thiết kế để tạo ra các số ngẫu nhiên an toàn. Đây là những gì tôi làm:

import os, hashlib 
def gen(): 
    return hashlib.sha1(os.urandom(512)).hexdigest() 

test = [gen() for i in range(100000)] 
print len(test), len(set(test)) 

... cần rất an toàn (nói, khó lấy chuỗi cookie phiên và đoán cookie phiên hiện tại khác).

+0

Tại sao Mersenne Twister không phù hợp để tạo cookie an toàn? Nó có một khoảng thời gian là 2 ** 19937, do đó bạn không nên dự đoán giá trị tiếp theo ngay cả khi bạn biết một vài giá trị tiếp theo. –

+3

Từ Wikipedia: "Thuật toán ở dạng bản địa của nó không phù hợp với mật mã (không giống như Blum Blum Shub). Quan sát đủ số lần lặp (624 trong trường hợp MT19937) cho phép ta dự đoán tất cả các lần lặp trong tương lai." (http://en.wikipedia.org/wiki/Mersenne_twister) –

+9

Chỉ vì một trình tạo số ngẫu nhiên có chu kỳ dài không có nghĩa là rất khó để lấy một chuỗi trong chu trình và tìm ra nó ở đâu. Nếu tôi cung cấp cho bạn chuỗi 0, 1, 2, 3 ..., nó có một chu kỳ rất dài (vô hạn), nhưng nó không quan trọng để tìm ra giá trị tiếp theo là gì. Bạn cần một chuỗi mã hóa an toàn - nơi khó xác định trạng thái của động cơ từ đầu ra của nó. Đó là những gì băm an toàn. Tôi thích băm uranium thông qua SHA-1, nhưng băm MT thông qua SHA-1 cũng có thể là tốt. –

-4

Để tránh sự cố, bạn có thể sử dụng một chuỗi cookie được đảm bảo khác (bạn có thể sử dụng tập hợp). Mỗi khi bạn đưa cookie cho ai đó, bạn lấy nó từ trình tự và bạn thêm một cookie khác vào nó. Một tùy chọn khác là tạo UUID và sử dụng nó làm cookie.

Cách khác để tránh sự cố có thể là giữ khóa riêng tư và sử dụng tổng kiểm tra (ví dụ MD5) của khóa riêng tư, với giá trị bộ đếm được liên kết với nó. Xác suất va chạm sẽ rất thấp. Để an toàn hơn, hãy thêm một vài biến vào tổng kiểm tra, như thời gian hiện tại, địa chỉ ip của người dùng, ...

Thư viện để tạo cookie tồn tại. Bất kỳ triển khai WSGI nào cũng có thể chứa trình tạo cookie.

Nếu bạn chỉ quan tâm đến chuỗi ngẫu nhiên của mình như thế nào, bạn có thể tạo một tệp với một triệu cookie và thực hiện kiểm tra ngẫu nhiên trên tệp đó. Điều này, tuy nhiên, không phải là những gì tôi muốn giới thiệu.

+0

Đây không phải là câu hỏi của tôi - tôi không muốn một công việc xung quanh; Tôi muốn hiểu chuyện gì đang xảy ra. Công việc của tôi là sử dụng os.urandom.Đối với việc sử dụng chuỗi - điều đó sẽ là xấu, vì cookie có thể được đoán. Sử dụng uuids: nếu trình tạo UUID sử dụng mô-đun ngẫu nhiên, chúng có thể không phải là duy nhất. –

+0

Một UUID * không thể * được đảm bảo là duy nhất. Vì lý do lý thuyết, bởi vì chỉ có 2 ** 128 trong số đó, và vì lý do thực tế, vì có lẽ mã tạo ra chúng là thiếu sót - đặc biệt nếu nó rất giống với mã tôi đăng, cũng nên tạo ra các giá trị duy nhất, nhưng không. –

+0

Sử dụng mã "không hoàn thiện" của người khác có thể tốt hơn trong tương lai so với thử công cụ của riêng bạn, trong đó bạn không biết nó thực sự làm gì. – pvoosten

3

này chắc chắn không phải là một vụ va chạm kịch bản bình thường:

  • 32 nhân vật với 62 tùy chọn cho mỗi ký tự tương đương với 190 bit (log2 (62) * 32)
  • Theo nghịch lý ngày sinh nhật, bạn nên nhận được xung đột một cách tự nhiên sau mỗi 2 ** 95 cookie, có nghĩa là không bao giờ

Đây có phải là vấn đề tương tranh không?

  • Nếu vậy, sử dụng khác nhau random.Random trường hợp cho mỗi thread
  • thể lưu những trường hợp trong lưu trữ thread-địa phương (threading.local())
  • Trên Linux, Python nên gieo rắc chúng bằng cách sử os.urandom() - không gian hệ thống - do đó bạn sẽ nhận các luồng khác nhau cho mỗi chuỗi.
+1

Ông cho biết nhiều quá trình FCGI, không phải chủ đề. Đúng vậy, Martin, hay bạn có ý là chủ đề? –

+1

Quy trình, chính xác. –

0

tôi phải xóa câu trả lời ban đầu của tôi, mà cho rằng máy phát điện không hạt từ /dev/urandom, vì nó source (đối với Python 3.x) nói rõ ràng rằng đó là:

def seed(self, a=None): 
    """Initialize internal state from hashable object. 

    None or no argument seeds from current time or from an operating 
    system specific randomness source if available. 

    If a is not None or an int or long, hash(a) is used instead. 
    """ 

    if a is None: 
     try: 
      a = int(_hexlify(_urandom(16)), 16) 
     except NotImplementedError: 
      import time 
      a = int(time.time() * 256) # use fractional seconds 

    super().seed(a) 
    self.gauss_next = None 

tôi do đó một cách khiêm nhường chấp nhận rằng có những điều bí ẩn trên thế giới mà tôi không thể giải mã được.

+1

Bạn nhìn thấy nó ở đâu từ một số hàm băm()? Trong random.py, quanh dòng 108, nó được tạo thành từ lâu (_hexlify (_urandom (16)), 16). –

+0

Thật vậy, tôi chỉ đọc bản thân mình. –

+0

Nếu bạn đang thực sự xem xét điều đó - có lẽ bước tiếp theo sẽ kiểm tra xem dòng 'a = int (_hexlify (_urandom (16)), 16)' không tăng 'NotImplementedError' vì một số lý do lạ? –

1
  1. Tôi không biết quy trình FCGI của bạn đang sinh ra như thế nào, nhưng có thể sử dụng fork() sau khi trình thông dịch Python bắt đầu (và mô-đun ngẫu nhiên đã được nhập bằng thứ gì đó) gieo hai quy trình 'random._inst s từ cùng một nguồn?

  2. Có thể đặt một số gỡ lỗi để kiểm tra xem nó có gieo giống chính xác từ urandom không và không quay trở lại hạt giống dựa trên thời gian ít nghiêm ngặt hơn?

và bình luận lại: man! Đó là tôi stumped sau đó; nếu RNG luôn có trạng thái khác nhau khi khởi động, tôi không thể thấy bạn có thể bị va chạm như thế nào. Kỳ dị. Sẽ phải đặt rất nhiều ghi nhật ký nhà nước để điều tra các trường hợp cụ thể dẫn đến va chạm, tôi đoán, có vẻ như rất nhiều công việc rà soát thông qua các bản ghi. Nó có thể là (1a) các máy chủ FCGI thường không ngã ba, nhưng đôi khi không (có thể dưới tải, hoặc một cái gì đó)?

Hoặc (3) một số vấn đề cấp cao hơn chẳng hạn như proxy HTTP bị hỏng truyền cùng một Tập hợp cookie cho nhiều khách hàng?

+0

Cảm ơn những ý tưởng: 1. Tôi đã đổ bỏ trạng thái của RNG khi khởi động, và tất cả chúng đều khác nhau. 2. Tôi đã có nó tạo ra các tập tin tốt (sử dụng urandom) và xấu (sử dụng thời gian); tập tin "tốt" đã được tạo; tệp không đúng. –