Khi một chương trình đang chạy, tất cả các đối tượng Python được lưu trữ tạm thời trong bộ nhớ hệ thống và khi chương trình kết thúc, tất cả bộ nhớ bị chiếm dụng sẽ được hệ điều hành thu hồi. Đây là một câu hỏi. Làm cách nào chúng ta có thể lưu trữ các đối tượng Python trong đĩa hoặc gửi chúng qua mạng?
Trong Python, bạn có thể sử dụng pickle để tuần tự hóa [giải tuần tự hóa] một cấu trúc đối tượng thành [từ] một luồng byte. Dưới đây là các phương pháp hay nhất để tẩy Python an toàn
Bởi Ashutosh Agrawal, cố vấn cao cấp, và Arvind Balaji, cố vấn liên kết, Synopsys
Pickle trong Python chủ yếu được sử dụng trong tuần tự hóa và giải tuần tự hóa cấu trúc đối tượng Python. Nói cách khác, đó là quá trình chuyển đổi một đối tượng Python thành luồng byte để lưu trữ nó trong tệp/cơ sở dữ liệu, duy trì trạng thái chương trình qua các phiên hoặc truyền dữ liệu qua mạng. Luồng byte được chọn có thể được sử dụng để tạo lại hệ thống phân cấp đối tượng ban đầu bằng cách bỏ chọn luồng. Toàn bộ quá trình này tương tự như tuần tự hóa đối tượng trong Java hoặc. Bọc lưới
Khi một luồng byte không được chọn, trước tiên mô-đun pickle sẽ tạo một phiên bản của đối tượng ban đầu và sau đó điền vào phiên bản đó bằng dữ liệu chính xác. Để đạt được điều này, luồng byte chỉ chứa dữ liệu dành riêng cho thể hiện đối tượng ban đầu. Nhưng chỉ có dữ liệu thôi có thể không đủ. Để giải nén thành công đối tượng, luồng byte đã chọn chứa các hướng dẫn cho trình giải mã để tái tạo lại cấu trúc đối tượng ban đầu cùng với các toán hạng lệnh, giúp điền vào cấu trúc đối tượng
Theo tài liệu mô-đun dưa chua, các loại sau có thể được ngâm
- Không, đúng và sai
- Số nguyên, số nguyên dài, số dấu phẩy động, số phức
- Chuỗi bình thường và Unicode
- Bộ dữ liệu, danh sách, bộ và từ điển chỉ chứa các đối tượng có thể chọn
- Các chức năng được xác định ở cấp cao nhất của mô-đun
- Các chức năng tích hợp được xác định ở cấp cao nhất của mô-đun
- Các lớp được định nghĩa ở cấp cao nhất của mô-đun
Pickle cho phép các đối tượng khác nhau khai báo cách chúng nên được ngâm bằng phương thức __reduce__. Bất cứ khi nào một đối tượng được chọn, phương thức __reduce__ được xác định bởi nó sẽ được gọi. Phương thức này trả về một chuỗi, có thể đại diện cho tên của toàn cục Python hoặc một bộ mô tả cách tái tạo lại đối tượng này khi giải nén
Nói chung, tuple bao gồm hai đối số
- Có thể gọi được [trong hầu hết các trường hợp sẽ là tên của lớp cần gọi]
- Các đối số được chuyển đến có thể gọi ở trên
Thư viện pickle sẽ chọn riêng từng thành phần của bộ dữ liệu và sẽ gọi đối tượng có thể gọi được trên các đối số được cung cấp để xây dựng đối tượng mới trong quá trình giải nén
Nguy hiểm khi ngâm trăn
Vì không có cách hiệu quả nào để xác minh luồng dưa chua được giải nén, nên có thể cung cấp mã shell độc hại làm đầu vào, gây ra việc thực thi mã từ xa. Kịch bản tấn công phổ biến nhất dẫn đến điều này là tin tưởng vào dữ liệu pickle thô nhận được qua mạng. Nếu kết nối không được mã hóa, dưa nhận được cũng có thể đã được sửa đổi trên dây. Một kịch bản tấn công khác là khi kẻ tấn công có thể truy cập và sửa đổi các tệp pickle được lưu trữ từ bộ đệm, hệ thống tệp hoặc cơ sở dữ liệu
Mã ví dụ sau thể hiện chữ ký và xác minh mật mã. Chữ ký mật mã, như đã đề cập ở trên, giúp phát hiện bất kỳ sự thay đổi nào của dữ liệu đã chọn. Khách hàng sử dụng HMAC để ký dữ liệu. Nó gửi giá trị thông báo cùng với dữ liệu được chọn đến máy chủ như hình bên dưới
Nếu bạn muốn lưu trữ [chọn] các đối tượng python vào một tệp pickle duy nhất mà không đi kèm với các mô-đun có định nghĩa lớp/hàm, bạn nên
- Sử dụng
greeter = Greeter[[greeting1, greeting2]] greeter.greet[]
9 thay vìBooyaa! Howdy!
0 - Sử dụng một số thủ thuật để lừa
greeter = Greeter[[greeting1, greeting2]] greeter.greet[]
9 tin rằng việc nhập khẩu đã thực sự được xác định trongBooyaa! Howdy!
2
Dưa chua với sự phụ thuộc
Khi bạn muốn chọn một đối tượng python để lưu trữ lâu dài, bạn có thể gặp sự cố. dưa chua không lưu trữ định nghĩa đối tượng khi dưa chua. Vì vậy, ví dụ: khi bạn xây dựng một
Booyaa! Howdy!3, sau đó chọn và bỏ chọn nó ở một vị trí khác, bạn cần phải xác định chính xác
Booyaa! Howdy!3 trước khi có thể tải pickle tại đích đích
def greeting1[]: return "Booyaa!" def greeting2[]: return "Howdy!" class Greeter: def __init__[self, greetings]: self.greetings = greetings def greet[self]: for greet in self.greetings: print[greet[]]
greeter = Greeter[[greeting1, greeting2]] greeter.greet[]
Booyaa! Howdy!
import pickle pickle.dump[greeter, open["greeter.pkl", "wb"]]
Nếu bây giờ bạn thử tải lời chào ở một nơi khác, bạn sẽ nhận được một
Booyaa! Howdy!5
Booyaa! Howdy!1
Giải pháp 1. Cũng lưu trữ mô-đun với các định nghĩa
Một cách giải quyết vấn đề này bằng cách lưu trữ định nghĩa lớp của
Booyaa! Howdy!6 trong
Booyaa! Howdy!7, nhập
Booyaa! Howdy!6 từ
Booyaa! Howdy!9 và sao chép
Booyaa! Howdy!7 cùng với
import pickle pickle.dump[greeter, open["greeter.pkl", "wb"]]1 vào vị trí bạn muốn bỏ chọn
Tuy nhiên, bây giờ bạn đã tạo một phụ thuộc mà bạn cần quản lý. Bạn luôn phải đảm bảo rằng bạn có sẵn phiên bản phù hợp của mô-đun phù hợp khi bạn muốn mở khóa. Đặc biệt đối với việc lưu trữ lâu dài các đối tượng python, điều này đang gây ra sự cố. Sẽ tốt hơn nếu bạn có thể có tất cả đối tượng và định nghĩa trong một tệp
Giải pháp 2. Dill để giải cứu
May mắn thay, có một sự thay thế độc lập cho
Booyaa! Howdy!0 được gọi là
greeter = Greeter[[greeting1, greeting2]] greeter.greet[]9, tiếc là không đi kèm với thư viện tiêu chuẩn, vì vậy bạn phải tự cài đặt nó.
import pickle pickle.dump[greeter, open["greeter.pkl", "wb"]]4
Điều thú vị về
greeter = Greeter[[greeting1, greeting2]] greeter.greet[]9 là nó lưu trữ các định nghĩa cùng với đối tượng, miễn là chúng được định nghĩa trong
Booyaa! Howdy!2. Trong trường hợp của chúng tôi, chúng là như vậy khi chúng tôi lưu trữ đối tượng lời chào với dill, chúng tôi thực sự có thể tải lại đối tượng ngay bây giờ
greeter = Greeter[[greeting1, greeting2]] greeter.greet[]3
greeter = Greeter[[greeting1, greeting2]] greeter.greet[]4
Nó đã làm việc
Nhưng chỉ lưu trữ các định nghĩa trong Booyaa!
Howdy!
2 chứ không phải trong các mô-đun
Giả sử chúng ta định nghĩa
Booyaa! Howdy!6 trong mô-đun
import pickle pickle.dump[greeter, open["greeter.pkl", "wb"]]9
người chào hỏi. py
greeter = Greeter[[greeting1, greeting2]] greeter.greet[]8
greeter = Greeter[[greeting1, greeting2]] greeter.greet[]9
Sau đó, dưa chua lại không tải được khi
Booyaa! Howdy!7 bị thiếu hoặc bỏ lỡ các định nghĩa đúng
Booyaa! Howdy!1
cách giải quyết. di chuyển các định nghĩa sang Booyaa!
Howdy!
2
Bạn có thể giải quyết vấn đề này bằng cách
Booyaa! Howdy!12 các định nghĩa đã nhập
greeter = Greeter[[greeting1, greeting2]] greeter.greet[]0
greeter = Greeter[[greeting1, greeting2]] greeter.greet[]1
Và điều này hoạt động
greeter = Greeter[[greeting1, greeting2]] greeter.greet[]2
Tránh sử dụng Booyaa!
Howdy!
13 trong Booyaa!
Howdy!
2
Tuy nhiên, nó hơi cồng kềnh để
Booyaa! Howdy!13 mọi thứ và bạn có thể muốn tự động hóa việc này cho người dùng của mình
Một cách để làm điều này là khai báo một classmethod
Booyaa! Howdy!16
sử dụng Booyaa!
Howdy!
17
chào mừng2. py
greeter = Greeter[[greeting1, greeting2]] greeter.greet[]3
Bây giờ bạn có thể nhập chính
greeter = Greeter[[greeting1, greeting2]] greeter.greet[]4
Booyaa! Howdy!
sử dụng Booyaa!
Howdy!
18
người chào3. py
greeter = Greeter[[greeting1, greeting2]] greeter.greet[]6
greeter = Greeter[[greeting1, greeting2]] greeter.greet[]7
Booyaa! Howdy!
Phần kết luận
Hy vọng điều này có thể hữu ích cho một số bạn muốn lưu trữ các đối tượng python và không lo lắng về các phụ thuộc mô-đun