Có an toàn khi sử dụng echo để truyền dữ liệu nhạy cảm vào chpasswd không?


17

Tôi đang cố gắng thiết lập hàng loạt mật khẩu tài khoản người dùng bằng cách sử dụng chpasswd. Mật khẩu nên được tạo ngẫu nhiên và được in ra stdout(tôi cần ghi lại hoặc đặt chúng vào một cửa hàng mật khẩu), và cũng được chuyển vào chpasswd.

Ngây thơ, tôi sẽ làm điều này như thế này

{
  echo student1:$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo '')
  echo student2:$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo '')
} | tee >(chpasswd)

Tuy nhiên, tôi lo lắng về việc chuyển mật khẩu mới dưới dạng đối số dòng lệnh echo, bởi vì các đối số thường hiển thị cho những người dùng khác ps -aux(mặc dù tôi chưa bao giờ thấy bất kỳecho dòng xuất hiện ps).

Có cách nào khác để thêm giá trị vào mật khẩu trả lại của tôi và sau đó chuyển nó vào chpasswdkhông?


6
echolà một vỏ tích hợp. Nó sẽ không xuất hiện trong bảng quy trình.
Kusalananda

Câu trả lời:


15

Mã của bạn phải an toàn vì echosẽ không hiển thị trong bảng quy trình vì nó được tích hợp sẵn.

Đây là một giải pháp thay thế:

#!/bin/bash

n=20
paste -d : <( seq -f 'student%.0f' 1 "$n" ) \
           <( tr -cd 'A-Za-z0-9' </dev/urandom | fold -w 13 | head -n "$n" ) |
tee secret.txt | chpasswd

Điều này tạo ra tên sinh viên và mật khẩu ncủa bạn, mà không cần chuyển bất kỳ mật khẩu nào trên bất kỳ dòng lệnh nào của bất kỳ lệnh nào.

Các pastekeo tiện ích cùng nhiều file như cột và chèn một dấu phân cách ở giữa chúng. Ở đây, chúng tôi sử dụng :như là dấu phân cách và cung cấp cho nó hai "tệp" (thay thế quy trình). Cái đầu tiên chứa đầu ra của một seqlệnh tạo ra 20 tên người dùng sinh viên và cái thứ hai chứa đầu ra của một đường ống tạo ra 20 chuỗi ngẫu nhiên có độ dài 13.

Nếu bạn có một tệp có tên người dùng đã được tạo:

#!/bin/bash

n=$(wc -l <usernames.txt)

paste -d : usernames.txt \
           <( tr -cd 'A-Za-z0-9' </dev/urandom | fold -w 13 | head -n "$n" ) |
tee secret.txt | chpasswd

Chúng sẽ lưu mật khẩu và tên người dùng vào tệp secret.txtthay vì hiển thị mật khẩu được tạo trong thiết bị đầu cuối.


2
Đó là một giải pháp thông minh không cần echohoặc printf, tuy nhiên, mã này hơi khó giải mã
Nils Werner

@NilsWerner Đã thêm một chút giải thích. Hãy cho tôi biết nếu có một điều cụ thể mà bạn muốn tôi mở rộng.
Kusalananda

1
Bạn không nên dựa vào echoviệc là một vỏ dựng sẵn. Trên hầu hết các shell nó là, nhưng hoàn toàn không có yêu cầu đó.
Austin Hemmelgarn

1
@Kusalananda Chỉ tò mò, có sự khác biệt hiệu quả giữa tee secret.txt > >(chpasswd)tee secret.txt | chpasswd? Loại thứ hai dường như phổ biến hơn nhiều, vì vậy tôi tự hỏi tại sao bạn lại chọn sử dụng thay thế quy trình thay vì ống trơn
Christopher Shroba

1
@ChristopherShroba Không có lý do nào khác ngoài mã tương tự với mã đã có trong câu hỏi (sử dụng thay thế quy trình với tee). Bây giờ bạn đã chỉ ra nó, tôi nghĩ rằng tôi thực sự sẽ thay đổi nó (nó có vẻ tốt hơn). Cảm ơn.
Kusalananda

8

echo rất có khả năng được tích hợp vào vỏ, vì vậy nó sẽ không xuất hiện trong ps một quy trình riêng biệt.

Nhưng bạn không cần phải sử dụng thay thế lệnh, bạn chỉ có thể có đầu ra từ đường ống trực tiếp đến chpasswd:

{  printf "%s:" "$username";
   head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo ''
} | chpasswd 

Nếu bạn muốn thay đổi nhiều mật khẩu chỉ với một lần chạy chpasswd, bạn nên dễ dàng lặp lại các phần thiết yếu. Hoặc biến nó thành một hàm:

genpws() {
    for user in "$@"; do
        printf "%s:" "$user";
        head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13
        echo
    done
}
genpws username1 username2... | chpasswd 

Như một bên: head /dev/urandomcảm thấy một chút kỳ lạ vì urandomkhông phải là định hướng dòng. Nó có thể đọc quá nhiều byte từ nó, điều này sẽ ảnh hưởng đến khái niệm entropy có sẵn của hạt nhân, điều này có thể dẫn đến /dev/randomviệc chặn. Có thể sạch hơn khi chỉ đọc một lượng dữ liệu cố định và sử dụng một cái gì đó nhưbase64 để chuyển đổi các byte ngẫu nhiên thành các ký tự có thể in được (thay vì chỉ ném đi khoảng 3/4 số byte bạn nhận được).

Một cái gì đó như thế này sẽ cung cấp cho bạn khoảng. 16 ký tự và số:

head -c 12 /dev/urandom | base64 | tr -dc A-Za-z0-9 

(nghĩa là, ít hơn 16 lượng +/ký tự trong đầu ra base64. Cơ hội là 1/32 cho mỗi ký tự, vì vậy nếu tôi có tổ hợp của mình đúng, điều đó mang lại khoảng 99% cơ hội để lại ít nhất 14 ký tự và 99,99% cơ hội rời khỏi ít nhất 12.)


printfGiải pháp của bạn không thực hiện được những gì mã gốc của tôi làm: trả lại nhiều dòng cho nhiều tên người dùng, nhưng tôi đánh giá cao nhận xét của bạn trênhead urandom
Nils Werner

@NilsWerner, tốt, tôi mặc dù việc mở rộng cho nhiều người dùng rõ ràng. Nhưng không vấn đề gì, chúng tôi có thể tạo một chức năng để tạo tên người dùng: cặp mật khẩu cho nhiều người dùng trong một lần. (xem chỉnh sửa)
ilkkachu

3
Bạn thực sự không thể dựa vào 10 "dòng" đầu tiên từ urandom chứa đủ các ký tự mà bạn muốn. Chỉ cần chạy urandom trực tiếp thông qua tr thay thế.
Kusalananda

@Kusalananda, ý bạn là head -c 10 | base64đường ống của tôi , hay của Nils với head | tr? 10 "dòng" byte ngẫu nhiên rất có thể là hàng trăm byte (với điều kiện chỉ 1 trong 256 sẽ là dòng mới), mặc dù về lý thuyết nó có thể chính xác là 10 byte, nhưng tỷ lệ đó là hoàn toàn không đáng kể. Tương tự như vậy khi sử dụng base64, nếu các byte ngẫu nhiên chỉ xảy ra \xff, thì base64 sẽ chỉ là một chuỗi các dấu gạch chéo, nhưng điều đó cũng khó xảy ra. Nếu bạn quan tâm, bạn có thể đọc hơn 10 byte, giảm tỷ lệ cược của điều đó và sau đó cắt giảm độ dài của kết quả đầu ra.
ilkkachu

1
@ilkkachu Tôi đang đề cập đến cả hai mã. Nếu bạn đọc các byte ngẫu nhiên và muốn một cái gì đó có độ dài cụ thể sau khi lọc ra những gì bạn không muốn, thì đừng cắt nguồn dữ liệu cho đến khi bạn chắc chắn rằng bạn có những gì bạn cần. Như bạn nói, rất khó có khả năng bạn nhận được một chuỗi mười dòng mới /dev/urandom, nhưng rủi ro không phải là 0%.
Kusalananda
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.