Có cách nào để truyền dữ liệu nhạy cảm trong bash bằng dấu nhắc cho bất kỳ lệnh nào không?


40

Giả sử rằng tôi đang sử dụng sha1passđể tạo ra một hàm băm của một số mật khẩu nhạy cảm trên dòng lệnh. Tôi có thể sử dụng sha1pass mysecretđể tạo ra một hàm băm mysecretnhưng điều này có nhược điểm mysecretlà trong lịch sử bash. Có cách nào để thực hiện mục tiêu cuối cùng của lệnh này trong khi tránh tiết lộ mysecretbằng văn bản đơn giản, có lẽ bằng cách sử dụng passwddấu nhắc kiểu?

Tôi cũng quan tâm đến một cách tổng quát để làm điều này để truyền dữ liệu nhạy cảm cho bất kỳ lệnh nào. Phương thức sẽ thay đổi khi dữ liệu nhạy cảm được truyền dưới dạng đối số (chẳng hạn như trong sha1pass) hoặc trên STDIN cho một số lệnh.

Có cách nào để hoàn thành việc này?


Chỉnh sửa : Câu hỏi này thu hút rất nhiều sự chú ý và đã có một số câu trả lời hay được đưa ra dưới đây. Tóm tắt là:

  • Theo câu trả lời của @ Kusalananda , lý tưởng nhất là người ta sẽ không bao giờ phải cung cấp mật khẩu hoặc bí mật làm đối số dòng lệnh cho tiện ích. Điều này dễ bị tổn thương theo nhiều cách như anh ta mô tả và người ta nên sử dụng một tiện ích được thiết kế tốt hơn có khả năng lấy đầu vào bí mật trên STDIN
  • Câu trả lời của @ vfbsilva mô tả cách ngăn chặn mọi thứ được lưu trữ trong lịch sử bash
  • Câu trả lời của @ Jonathan mô tả một phương pháp hoàn toàn tốt để thực hiện điều này miễn là chương trình có thể lấy dữ liệu bí mật của nó trên STDIN. Như vậy, tôi đã quyết định chấp nhận câu trả lời này. sha1passtrong OP của tôi chỉ là một ví dụ, nhưng cuộc thảo luận đã xác định rằng các công cụ tốt hơn tồn tại lấy dữ liệu trên STDIN.
  • như @R .. lưu ý trong câu trả lời của anh ấy , sử dụng mở rộng lệnh trên một biến là không an toàn.

Vì vậy, tóm lại, tôi đã chấp nhận câu trả lời của @ Jonathan vì đó là giải pháp tốt nhất cho rằng bạn có một chương trình được thiết kế tốt và hoạt động tốt để làm việc. Mặc dù việc truyền mật khẩu hoặc bí mật làm đối số dòng lệnh về cơ bản là không an toàn, các câu trả lời khác cung cấp các cách để giảm thiểu các mối quan tâm bảo mật đơn giản.


6
Không chỉ vậy: Bất kỳ ai trên cùng một máy có quyền liệt kê các quy trình đang chạy đều có khả năng thấy nó sha1pass mysecretđang chạy và do đó biết đó mysecretlà gì . (Điều này chỉ hoạt động trong vài giây trong khi chương trình đang thực sự chạy, tất nhiên ...)
Toán

@MathologistsOrchid Điều này có thể tránh được bằng cách chạy trong một máy ảo riêng. Nhưng đó có thể là quá nhiều công việc để thiết lập để chỉ tạo một mật khẩu duy nhất ... :-)
Kusalananda

5
@Kusalananda Quan điểm của tôi là "đừng bao giờ đưa dữ liệu nhạy cảm vào dòng lệnh, ngay cả khi bạn tìm ra cách tắt lịch sử lệnh" ...
Toán

2
Chỉ để bạn biết, SHA-1 không được dùng cho băm khóa hoặc mật khẩu kể từ một vài năm nay.
David Foerster

2
Lưu ý rằng nếu hệ thống đang chạy một trình nền kiểm toán, tất cả các lệnh và tất cả các đối số của tất cả người dùng đều được ghi nhật ký tập trung bằng root, vì vậy bất kỳ ai có thể truy cập vào các nhật ký đó đều sẽ thấy điều này.
Randall

Câu trả lời:


20

Nếu sử dụng shell zshhoặc bash, hãy sử dụng tùy chọn -s cho readshell dựng sẵn để đọc một dòng từ thiết bị đầu cuối mà không lặp lại nó.

IFS= read -rs VARIABLE < /dev/tty

Sau đó, bạn có thể sử dụng một số chuyển hướng ưa thích để sử dụng biến như stdin.

sha1pass <<<"$VARIABLE"

Nếu bất cứ ai chạy ps, tất cả những gì họ sẽ thấy là "sha1pass".

Điều đó giả định rằng sha1passđọc mật khẩu từ stdin (trên một dòng, bỏ qua dấu phân cách dòng) khi không đưa ra bất kỳ đối số nào.


Tôi tin rằng chúng tôi đã thiết lập sha1passkhông sử dụng luồng đầu vào tiêu chuẩn của nó.
Kusalananda

@Kusalananda Được rồi, nhưng phương pháp này sẽ hoạt động cho các chương trình đọc từ stdin.
Jonathan

Vì vậy, giả sử tiện ích có thể lấy đầu vào bí mật của nó trên STDIN, đây có phải là giải pháp hợp lý và an toàn, bảo mật?
hỏa táng

Tôi đã quyết định chấp nhận câu trả lời này, cho rằng đó là giải pháp tốt nhất cho rằng bạn có một chương trình được thiết kế tốt để làm việc. sha1passchỉ là một ví dụ trong OP của tôi, và rõ ràng không phải là lựa chọn tốt nhất để sử dụng cho việc này.
hỏa táng

1
@cemulation, ... không an toàn trên một dòng lệnh . Trong ngữ cảnh của một di sản hoặc di truyền (như trong câu trả lời ở đây), nó không được tiếp xúc ps, nhưng có thể được ghi vào một tệp tạm thời - nếu ai đó muốn tránh điều đó, thì sshpass < <(printf '%s\n' "$VARIABLE")có thể được xem xét (vì printflà một nội dung, không phải là một lệnh bên ngoài, nó không được chuyển đến execvvà có thể truy cập thông qua ps).
Charles Duffy

35

Lý tưởng nhất, bạn không bao giờ nhập mật khẩu văn bản rõ ràng trên dòng lệnh làm đối số cho lệnh. Làm như vậy làm cho mật khẩu trở thành một đối số cho lệnh và các đối số dòng lệnh có thể được nhìn thấy trong bảng quy trình bằng cách sử dụng các công cụ đơn giản như pshoặc đăng nhập vào một số nhật ký kiểm toán.

Phải nói rằng, chắc chắn có nhiều cách để ẩn mật khẩu thực tế khỏi lịch sử lệnh của shell.

sha1pass "$( head -n 1 )"

Sau đó nhập mật khẩu và nhấn Enter. Các headlệnh sử dụng ở đây chấp nhận chính xác một dòng đầu vào và xuống dòng cuối cùng mà bạn gõ sẽ không là một phần của dữ liệu được truyền cho sha1pass.

Để ngăn các nhân vật lặp lại:

sha1pass "$( stty -echo; head -n 1; stty echo )"

Các stty -echolệnh tắt lặp lại của các ký tự gõ vào thiết bị đầu cuối. Tiếng vang sau đó được khôi phục với stty echo.

Để truyền vào đầu vào tiêu chuẩn, lệnh cuối cùng có thể được thay đổi (bạn sẽ thực hiện điều này nếu sha1passdữ liệu được chấp nhận trên đầu vào tiêu chuẩn, nhưng xuất hiện như thể tiện ích cụ thể này đang bỏ qua đầu vào tiêu chuẩn của nó):

{ stty -echo; head -n 1; stty echo; } | somecommand

Nếu bạn cần đầu vào nhiều dòng (ở trên giả sử một dòng duy nhất được thông qua, không có ký tự dòng mới ở cuối), sau đó thay thế toàn bộ headlệnh bằng catvà chấm dứt đầu vào (giả sử somecommandchính nó đọc cho đến khi kết thúc tệp) bằng Ctrl+D( theo sau Returnnếu bạn muốn bao gồm một ký tự dòng mới trong đầu vào, hoặc hai lần nếu không).

Điều này sẽ hoạt động bất kể bạn đang sử dụng loại vỏ nào (miễn là nó giống như vỏ Bourne hoặc giống như RC).

Một số shell có thể được thực hiện để không lưu các lệnh đã nhập trong tệp lịch sử của chúng nếu lệnh được đặt trước dấu cách. Điều này thường liên quan đến việc phải đặt thành HISTCONTROLgiá trị ignorespace. Điều này được hỗ trợ bởi ít nhất bashkshtrên OpenBSD, nhưng không phải bằng ví dụ ksh93hoặc dash. zshNgười dùng có thể sử dụng histignorespacetùy chọn hoặc HISTORY_IGNOREbiến của họ để xác định mẫu cần bỏ qua.

Trong shell hỗ trợ đọc readmà không lặp lại ký tự cho thiết bị đầu cuối, bạn cũng có thể sử dụng

IFS= read -rs password     # -s turns off echoing in bash or zsh
                           # -r for reading backslashes as-is,
                           # IFS= to preserve leading and trailing blanks
sha1pass "$password"

nhưng điều này rõ ràng vẫn có cùng một vấn đề với khả năng tiết lộ mật khẩu trong bảng quy trình.

Nếu tiện ích đọc từ đầu vào tiêu chuẩn và nếu shell hỗ trợ "chuỗi-đây", thì ở trên có thể được thay đổi thành

IFS= read -rs password
somecommand <<<"$password"

Tóm tắt ý kiến ​​dưới đây:

  • Thực thi một lệnh với mật khẩu được cung cấp trên dòng lệnh, mà tất cả các lệnh trên thực hiện, ngoại trừ lệnh truyền dữ liệu vào lệnh, sẽ có khả năng hiển thị mật khẩu cho bất kỳ ai đang chạy pscùng một lúc. Tuy nhiên, không có lệnh nào ở trên sẽ lưu mật khẩu đã nhập trong tệp lịch sử của shell nếu được thực thi từ shell tương tác.

  • Các chương trình hoạt động tốt đọc mật khẩu văn bản rõ ràng sẽ làm như vậy bằng cách đọc từ đầu vào tiêu chuẩn của chúng, từ một tệp hoặc trực tiếp từ thiết bị đầu cuối.

  • sha1pass không yêu cầu mật khẩu trên dòng lệnh, được nhập trực tiếp hoặc sử dụng một số hình thức thay thế lệnh.

  • Nếu có thể, sử dụng một công cụ khác.


11
Điều này là không chính xác. Kết quả của việc mở rộng lệnh $(...)sẽ là một phần của dòng lệnh và hiển thị trong psđầu ra ngoại trừ trên một hệ thống có độ cứng / Proc.
R ..

3
@Kusalananda, thậm chí ghi đè lên argv sau khi bạn bắt đầu để lại một cửa sổ dễ bị tổn thương trước khi việc ghi đè đó diễn ra; đó là một sự giảm thiểu, không phải là một sửa chữa.
Charles Duffy

5
@Kusalananda, không có chương trình nào được thiết kế tốt để băm mật khẩu sẽ yêu cầu nhập vào dòng lệnh, vì vậy về cơ bản điều kiện là có sẵn - nếu không , người ta nên chọn một công cụ khác.
Charles Duffy

4
@CharlesDuffy: Công cụ ở đây dường như bị hỏng cơ bản. sha1passchạy không có mật khẩu trên dòng lệnh dường như tạo ra một đầu ra mà không đọc bất cứ điều gì ... Vì vậy, OP cần chọn một công cụ khác.
R ..

8
Câu trả lời này không an toàn từ góc độ bảo mật và ưu điểm duy nhất là mật khẩu không hiển thị trong lịch sử hệ vỏ, nhưng lợi thế đó dễ thực hiện hơn bằng cách bao gồm một khoảng
trắng

25

Nếu bạn đặt HISTCONTROLnhư vậy:

HISTCONTROL=ignorespace

và bắt đầu lệnh với khoảng trắng:

~$  mycommand

nó sẽ không được lưu trữ trong lịch sử.


10

Truyền dữ liệu nhạy cảm qua đường ống hoặc tài liệu tại đây:

command_with_secret_output | command_with_secret_input

hoặc là:

command_with_secret_input <<EOF
$secret
EOF

Sẽ rất tốt nếu các bí mật nằm trong các biến shell (không xuất), nhưng bạn không bao giờ có thể sử dụng các biến đó trên các dòng lệnh, chỉ trong các tài liệu và nội bộ shell ở đây.

Như Kusalananda đã lưu ý trong một nhận xét, nếu bạn nhập lệnh trong trình bao tương tác, các dòng bạn nhập cho tài liệu ở đây sẽ được lưu trong lịch sử trình bao, vì vậy sẽ không an toàn khi nhập mật khẩu ở đó, nhưng vẫn nên an toàn để sử dụng các biến shell chứa bí mật; lịch sử sẽ chứa văn bản $secretchứ không phải bất cứ điều gì được $secretmở rộng.

Sử dụng mở rộng lệnh không an toàn :

command_with_secret_input "$(command_with_secret_output)"

bởi vì đầu ra sẽ được bao gồm trên dòng lệnh và hiển thị trong psđầu ra (hoặc đọc thủ công từ / Proc) ngoại trừ trên các hệ thống có độ cứng / Proc.

Việc gán cho một biến cũng không sao:

secret=$(command_with_secret_output)

Những gì tôi đang tìm kiếm là một lệnh thực tế command_with_secret_outputcho phép tôi nhập đầu ra bí mật. Liệu một lệnh như vậy tồn tại có thể được thay thế ở đây?
hỏa táng

Lưu ý rằng việc nhập tài liệu ở đây trong bash phiên tương tác sẽ lưu tài liệu vào tệp lịch sử.
Kusalananda

@cemulation: Chỉ cần sử dụng shell dựng sẵn read, vd read -r secret. Sau đó, bí mật của bạn là trong $secret. Bạn có thể chạy stty trước / sau nó để ẩn đầu vào nếu bạn muốn.
R ..

3
@Kusalananda: sha1passdường như bị hỏng cơ bản / không thể sử dụng / không an toàn vì không thể đọc mật khẩu từ stdin hoặc tệp. Một tiện ích khác nhau là cần thiết để giải quyết vấn đề, tôi nghĩ vậy.
R ..

1
@cemulation Nhận xét cuối cùng của bạn cho R là chính xác tại chỗ. Đó là lý do tại sao nó sẽ không giúp đỡ. read -rssẽ thực hiện công việc (nếu bạn bao gồm -rđể có thể có mật khẩu có dấu gạch chéo ngược trong đó), nhưng sau đó bạn sẽ có khả năng hiển thị mật khẩu trong danh sách quy trình (và tùy thuộc vào việc kế toán quy trình có được bật hay không và cách cấu hình , trong quá trình kế toán nhật ký là tốt).
Kusalananda

6

Chỉ cần viết giá trị vào một tệp và truyền tệp:

$ cat > mysecret
Big seecreeeet!
$ cat mysecret | sha1pass 

Tôi không chắc cách thức sha1passhoạt động, nếu nó có thể lấy một tệp làm đầu vào, bạn có thể sử dụng sha1pass < mysecret. Nếu không, việc sử dụng catcó thể là một vấn đề vì nó bao gồm dòng mới cuối cùng. Nếu đó là trường hợp, sử dụng (nếu headhỗ trợ của bạn -c):

head -c-1 mysecret | sha1pass 

2
Tại sao ghi mật khẩu vào đĩa trong ví dụ đầu tiên của bạn khi bạn chỉ có thể làm cat | sha1pass? cat mysecret | sha1passsha1pass < mysecretcó hành vi tương tự đối với các dòng mới cuối cùng. catkhông thêm dòng mới. Dù sao, nếu sha1passhỗ trợ chuyển mật khẩu thông qua đầu vào tiêu chuẩn, tôi sẽ hy vọng nó sẽ bỏ qua dòng mới cuối cùng. Rốt cuộc, các tệp có dòng không bị chấm dứt bởi dòng mới là không tự nhiên trong unix, vì vậy sẽ rất khó để mong đợi một tệp không bị chấm dứt bởi một dòng mới.
JoL

@JoL i) bởi vì tôi đã không nghĩ về điều đó: / Nhưng nó sẽ hoạt động như thế nào? cat | sha1passdường như chạy sha1passtrước khi cho tôi cơ hội nhập bất kỳ đầu vào nào. ii) Không, tất nhiên cat mysecretkhông thêm một dòng mới, tôi chưa bao giờ nói catthêm nó, chỉ có nó bao gồm nó.
terdon

Tôi hiểu, nhưng nó cũng không giống như < mysecretloại bỏ nó. :)
JoL

Đừng bận tâm. Bây giờ tôi đọc lại, tôi thấy rằng bạn nói rằng để sau này cầu hôn head -c-1. Tôi đoán tôi chỉ bối rối về lý do tại sao sử dụng cat mysecret | sha1passvà sau đó đề xuất sha1pass < mysecret. Tôi đoán điều đáng lo ngại là sha1pass có thể phàn nàn về các tệp thông thường cho stdin; Tôi cung không chăc tại sao.
JoL

@JoL còn hơn thế nữa vì tôi chưa bao giờ sử dụng sha1passvà không thể tìm thấy hướng dẫn sử dụng hoặc -hbất kỳ hình thức tài liệu nào khác trong vài phút tôi đã dành để tìm kiếm và vì vậy không thể tìm ra nếu chạy sha1pass foođược xử lý foonhư một chuỗi đầu vào hoặc dưới dạng tệp đầu vào . Do đó tôi đã đưa ra các lựa chọn để đối phó với từng khả năng.
terdon

1

Nếu những gì terdon đã làm là có thể, thì đó là giải pháp tốt nhất, thông qua đầu vào tiêu chuẩn. Vấn đề duy nhất còn lại là anh ấy đã viết mật khẩu vào đĩa. Chúng ta có thể làm điều này thay vào đó:

stty -echo
echo -n "password: "
head -1 | sha1pass
stty echo

Giống như Kusalananda đã nói, stty -echođảm bảo những gì bạn gõ không được nhìn thấy cho đến khi bạn làm stty echolại. head -1sẽ nhận được một dòng từ đầu vào tiêu chuẩn và chuyển nó vào sha1pass.


0

tôi sẽ dùng

sha1pass "$(cat)"

catsẽ đọc từ stdin cho đến khi EOFcó thể gây ra bằng cách nhấn Ctrl + D. Sau đó, kết quả sẽ được chuyển thành đối số chosha1pass


3
Câu trả lời của R .. giải thích tại sao điều này không an toàn.
hvd
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.