Bạn không cần tệp tạm để tạo khóa OpenVPN
Giữ vật liệu khóa trong bộ nhớ giúp tránh vòng đời của tệp, chứ không tránh rò rỉ. Hãy tách luồng đầu ra và luồng lỗi, và sau đó coi khóa là một bí mật.
Việc tạo khóa không cần một tệp tạm, và bỏ được nó thì sửa được ít hơn nhiều so với điều mà hầu hết các hướng dẫn ngụ ý. Thứ nó loại bỏ là vòng đời của một tệp cùng cuộc đua dọn dẹp quanh đó. Thứ nó không đụng tới là mọi cơ hội làm lộ bí mật về sau. Vấn đề đúng đắn trong những kịch bản này thường nằm ở chỗ khác, bởi vì chẩn đoán và vật liệu khóa đi trên những luồng khác nhau.
Tệp chưa bao giờ là mức phơi bày như bạn tưởng
Một tệp tạm là rủi ro cụ thể khi nó cho mọi người đọc, khi nó sống sót qua một lần sập, hoặc khi một bước dọn dẹp bị bỏ qua sau một ngoại lệ. Những điều đó là thật, và chúng đáng được sửa. Chúng cũng mang tính cục bộ, hữu hình và dễ kiểm thử. Hãy gọi tên từng cái trong kịch bản của chính bạn trước khi kết luận rằng thay đổi này chỉ là bề ngoài.
Những rủi ro lặng lẽ hơn nằm ở phía hạ nguồn: khóa bị in ra khi gỡ lỗi, ngoại lệ tuần tự hóa toàn bộ đối tượng kết quả, trình xử lý sập ghi ra một core dump, bộ tổng hợp nhật ký nhận đường dẫn tệp rồi sau đó nhận nội dung. Việc tránh một tệp tạm không giúp gì cho bất kỳ điều nào trong số đó, và tin rằng nó có giúp chính là cách một lần viết lại với ý định tốt khiến bí mật bị phơi ra nhiều hơn trước. Hãy coi thay đổi này là một cải tiến trong một chuỗi, chứ không phải là bản sửa.
Ứng dụng khách ghi ra gì khi không có tên tệp
Các phiên bản hiện tại của ứng dụng khách gửi khóa được tạo ra đầu ra chuẩn khi lệnh tạo khóa được đưa ra mà không có đường dẫn đầu ra. Chính hành vi đã được ghi tài liệu đó khiến cách làm trong bộ nhớ khả thi, và nó loại bỏ nhu cầu dùng mẹo cũ là trỏ công cụ vào một đường dẫn thiết bị.
import subprocess
proc = subprocess.run(
["openvpn", "--genkey", "tls-crypt"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=True,
)
key_material = proc.stdout
Hãy truyền lệnh dưới dạng một danh sách. Ở đây không cần shell mở rộng, và việc bật shell sẽ khiến ranh giới đối số phụ thuộc vào cách trích dẫn mà bạn không kiểm soát. Hãy dùng đúng tệp thực thi dự định bằng đường dẫn tuyệt đối nếu kịch bản có thể chạy với một đường dẫn tìm kiếm khác với điều bạn mong đợi.
Việc kiểm tra mã trả về giữ cho nhánh thành công không tiếp tục sau một lần gọi thất bại. Không có nó, một chuỗi byte rỗng có thể chảy tiếp và chỉ thất bại rất lâu sau đó, tại điểm mà khóa được dùng và thông báo lỗi không còn nhắc gì đến việc tạo khóa nữa.
Hai luồng, hai ý nghĩa
Đầu ra chuẩn mang khóa. Đầu ra lỗi mang mọi thứ công cụ muốn nói với bạn, kể cả các cảnh báo về cấu hình, phiên bản và loại khóa. Việc chuyển hướng cả hai vào cùng một bộ đệm là sai lầm tạo ra một khóa trông có vẻ hợp lý với một câu bị khâu vào giữa.
Hãy giữ nhánh thất bại riêng ra. Khi lần gọi thất bại, hãy báo lệnh đã thất bại và trạng thái thoát, rồi quyết định một cách có chủ đích xem có phần nào của đầu ra lỗi là an toàn để hiển thị. Đổ toàn bộ đối tượng kết quả vào nhật ký là lối tắt thường thấy, và nó có thể mang theo khóa.
Đọc theo cách an toàn với dữ liệu nhị phân rất quan trọng nếu sau này bạn băm hoặc so sánh vật liệu. Chế độ văn bản với một bảng mã ngoài dự kiến có thể làm thay đổi những byte vốn không được coi là văn bản, và một khóa bị thay đổi thì không thể phân biệt với một khóa sai cho tới khi một lần bắt tay thất bại.
Nếu bạn thực sự lưu nó lại, hãy làm một cách có chủ đích
Hầu hết các triển khai cuối cùng đều cần khóa trên đĩa, trên cổng kết nối hoặc trong một kho bí mật. Hãy ghi nó một lần, với quyền hạn chế ngay từ lúc tạo chứ không phải chmod sau đó, và làm cho việc ghi mang tính nguyên tử để một tệp dở dang không bao giờ trở thành tệp mà dịch vụ đọc lúc khởi động. Một lệnh đổi tên từ một đường dẫn trong cùng thư mục thường là đủ cho việc đó. Hãy xóa đường dẫn tạm trên nhánh thất bại, vì lần ghi thất bại chính là bản sao mà người ta hay quên.
Hãy đặt chế độ tệp khi tệp được tạo, và giữ chế độ thư mục cũng chặt chẽ như vậy. Tránh mọi đường dẫn nằm dưới một vị trí mà một tác vụ sao lưu quét qua mà không nghĩ ngợi, bởi vì một bí mật trong bản sao lưu hằng đêm là một bí mật trong mọi bản sao của bản sao lưu đó. Lập luận tương tự cũng áp dụng cho một ổ đĩa chia sẻ mà các dịch vụ khác có thể đọc.
Khóa chia sẻ không phải là danh tính
Việc tạo vật liệu này không cấp chứng chỉ, không ghi danh một ứng dụng khách và không xác lập ai đang kết nối. Khóa chia sẻ bảo vệ một kênh giữa các bên vốn đã tin nhau; danh tính vẫn đến từ chứng chỉ và bất kỳ cơ chế xác thực nào nằm trước nó.
Các loại khóa cũng không thể hoán đổi cho nhau. Một khóa đối xứng cho một tính năng không thể thay thế trực tiếp cho một tính năng khác, và các bản phát hành mới hơn thêm những biến thể riêng với các tệp khác nhau ở mỗi đầu. Hãy tạo đúng loại mà cấu hình của bạn thực sự nêu tên, rồi dùng nó theo vai trò mà loại đó định nghĩa.
Hãy kiểm tra kết quả bằng một kết nối thật thay vì xem kích thước tệp. Nếu cuộc bắt tay hoàn tất và nhật ký không hiện cảnh báo nào về khóa, thì đường tạo khóa là đúng; nếu khóa bị cắt ngắn bởi một luồng bị gộp, kết nối sẽ thất bại theo cách đổ lỗi cho đối tác thay vì cho kịch bản.