Env x = '() {:;}; lệnh 'bash do và tại sao nó không an toàn?


237

Rõ ràng có một lỗ hổng (CVE-2014-6271) trong bash: Bash tấn công tiêm mã biến môi trường được chế tạo đặc biệt

Tôi đang cố gắng tìm hiểu những gì đang xảy ra, nhưng tôi không hoàn toàn chắc chắn rằng tôi hiểu nó. Làm thế nào có thể echođược thực hiện như nó là trong dấu ngoặc đơn?

$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
vulnerable
this is a test

EDIT 1 : Một hệ thống được vá trông như thế này:

$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'
this is a test

EDIT 2 : Có một lỗ hổng / bản vá liên quan: CVE-2014-7169 sử dụng thử nghiệm hơi khác:

$ env 'x=() { :;}; echo vulnerable' 'BASH_FUNC_x()=() { :;}; echo vulnerable' bash -c "echo test"

đầu ra chưa từng có :

vulnerable
bash: BASH_FUNC_x(): line 0: syntax error near unexpected token `)'
bash: BASH_FUNC_x(): line 0: `BASH_FUNC_x() () { :;}; echo vulnerable'
bash: error importing function definition for `BASH_FUNC_x'
test

đầu ra được vá một phần (phiên bản đầu) :

bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'
bash: error importing function definition for `BASH_FUNC_x()'
test

đầu ra được vá lên đến và bao gồm CVE-2014-7169:

bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `BASH_FUNC_x'
test

EDIT 3 : câu chuyện tiếp tục với:


Đó không phải là tiếng vang được thực thi. định nghĩa hàm của x. Nếu hàm được định nghĩa trong x thực hiện một số công việc lén lút, không có cách nào bash có thể kiểm tra giá trị trả về nếu hàm x là thực. Lưu ý chức năng trống trong mã kiểm tra. Một giá trị trả về không được kiểm tra có thể dẫn đến tiêm script. Script script dẫn đến leo thang đặc quyền và leo thang đặc quyền dẫn đến truy cập root. Bản vá vô hiệu hóa việc tạo x là một hàm
eyoung100

26
eyoung100, không có tiếng vang đang nhận được thực hiện. Bạn có thể thấy nó đang được thực thi vì từ vulnerablexuất hiện trong đầu ra. Vấn đề chính là bash đang phân tích cú pháp và thực thi mã sau khi định nghĩa hàm là tốt. Xem /bin/idphần của seclists.org/oss-sec/2014/q3/650 để biết ví dụ khác.
Mikel

4
Chỉ cần một bình luận bên nhanh. Red Hat đã khuyên rằng bản vá đã được phát hành chỉ là bản vá một phần và khiến các hệ thống vẫn có nguy cơ.
Peter

2
@ eyoung100 sự khác biệt là mã bên trong hàm chỉ thực thi khi biến môi trường được gọi rõ ràng. Mã sau khi định nghĩa hàm thực thi mỗi khi một quá trình Bash mới bắt đầu.
David Farrell

1
Xem stackoverflow.com/questions/26022248/ cấp để biết thêm chi tiết
Barmar

Câu trả lời:


204

bash lưu trữ định nghĩa hàm xuất dưới dạng biến môi trường. Các hàm được xuất trông như thế này:

$ foo() { bar; }
$ export -f foo
$ env | grep -A1 foo
foo=() {  bar
}

Đó là, biến môi trường foocó nội dung theo nghĩa đen:

() {  bar
}

Khi một phiên bản mới của bash khởi chạy, nó sẽ tìm các biến môi trường được chế tạo đặc biệt này và diễn giải chúng như các định nghĩa hàm. Bạn thậm chí có thể tự viết một cái và thấy rằng nó vẫn hoạt động:

$ export foo='() { echo "Inside function"; }'
$ bash -c 'foo'
Inside function

Thật không may, việc phân tích cú pháp các định nghĩa hàm từ các chuỗi (các biến môi trường) có thể có hiệu ứng rộng hơn dự định. Trong các phiên bản chưa được vá, nó cũng diễn giải các lệnh tùy ý xảy ra sau khi chấm dứt định nghĩa hàm. Điều này là do các ràng buộc không đủ trong việc xác định các chuỗi giống như hàm chấp nhận được trong môi trường. Ví dụ:

$ export foo='() { echo "Inside function" ; }; echo "Executed echo"'
$ bash -c 'foo'
Executed echo
Inside function

Lưu ý rằng tiếng vang bên ngoài định nghĩa hàm đã được thực hiện bất ngờ trong quá trình khởi động bash. Định nghĩa hàm chỉ là một bước để đánh giá và khai thác xảy ra, chính định nghĩa hàm và biến môi trường được sử dụng là tùy ý. Shell nhìn vào các biến môi trường, nhìn thấy foo, có vẻ như nó đáp ứng các ràng buộc mà nó biết về định nghĩa hàm trông như thế nào và nó đánh giá dòng, vô tình cũng thực hiện tiếng vang (có thể là bất kỳ lệnh nào, độc hại hay không).

Điều này được coi là không an toàn bởi vì các biến thường không được phép hoặc dự kiến, trực tiếp gây ra việc gọi mã tùy ý có trong chúng. Có lẽ chương trình của bạn đặt các biến môi trường từ đầu vào của người dùng không tin cậy. Sẽ rất bất ngờ khi các biến môi trường đó có thể bị thao túng theo cách mà người dùng có thể chạy các lệnh tùy ý mà không có ý định rõ ràng của bạn để làm như vậy bằng cách sử dụng biến môi trường đó vì lý do được khai báo trong mã.

Dưới đây là một ví dụ về một cuộc tấn công khả thi. Bạn chạy một máy chủ web chạy shell dễ bị tổn thương, ở đâu đó, như một phần của vòng đời của nó. Máy chủ web này chuyển các biến môi trường cho tập lệnh bash, ví dụ: nếu bạn đang sử dụng CGI, thông tin về yêu cầu HTTP thường được bao gồm dưới dạng các biến môi trường từ máy chủ web. Ví dụ: HTTP_USER_AGENTcó thể được đặt thành nội dung của tác nhân người dùng của bạn. Điều này có nghĩa là nếu bạn giả mạo tác nhân người dùng của mình thành một cái gì đó như '() {:; }; echo foo ', khi kịch bản shell đó chạy, echo foosẽ được thực thi. Một lần nữa, echo foocó thể là bất cứ điều gì, độc hại hoặc không.


3
Điều này có thể ảnh hưởng đến bất kỳ lớp vỏ giống Bash nào khác không, như Zsh?
Amelio Vazquez-Reina

3
@ user815423426 Không, zsh không có tính năng này. Ksh có nó nhưng được thực hiện khác nhau, tôi nghĩ rằng các chức năng chỉ có thể được truyền trong các trường hợp rất hẹp, chỉ khi vỏ forks, không thông qua môi trường.
Gilles

20
@ user815423426 RC là trình bao khác chuyển các hàm trong môi trường, nhưng nó có biến có tên tiền tố là "fn_" và chúng chỉ được hiểu khi được gọi.
Stéphane Chazelas

18
@ StéphaneChazelas - cảm ơn bạn đã báo cáo lỗi.
Deer Hunter

13
@gnclmorais Ý bạn là bạn chạy export bar='() { echo "bar" ; }'; zsh -c barvà nó hiển thị barchứ không phải zsh:1: command not found: bar? Bạn có chắc chắn rằng bạn không nhầm lẫn cái vỏ bạn đang gọi với cái vỏ mà bạn đang sử dụng để thiết lập thử nghiệm không?
Gilles

85

Điều này có thể giúp chứng minh thêm những gì đang diễn ra:

$ export dummy='() { echo "hi"; }; echo "pwned"'
$ bash
pwned
$

Nếu bạn đang chạy shell dễ bị tổn thương, thì khi bạn bắt đầu một lớp con mới (ở đây, chỉ bằng cách sử dụng câu lệnh bash), bạn sẽ thấy mã tùy ý ( echo "pwned") ngay lập tức được thực thi như là một phần của việc bắt đầu. Rõ ràng, shell thấy rằng biến môi trường (giả) chứa định nghĩa hàm và đánh giá định nghĩa để xác định hàm đó trong môi trường của nó (lưu ý rằng nó không thực thi hàm: sẽ in 'hi'.)

Thật không may, nó không chỉ đánh giá định nghĩa hàm, nó đánh giá toàn bộ văn bản của giá trị của biến môi trường, bao gồm cả (các) câu lệnh độc hại có thể tuân theo định nghĩa hàm. Lưu ý rằng nếu không có định nghĩa hàm ban đầu, biến môi trường sẽ không được đánh giá, nó sẽ chỉ được thêm vào môi trường dưới dạng một chuỗi văn bản. Như Chris Down đã chỉ ra, đây là một cơ chế cụ thể để thực hiện việc nhập các hàm shell đã xuất.

Chúng ta có thể thấy hàm đã được xác định trong shell mới (và nó đã được đánh dấu là xuất ở đó) và chúng ta có thể thực thi nó. Hơn nữa, hình nộm chưa được nhập dưới dạng biến văn bản:

$ declare -f
dummy ()
{
    echo "hi"
}
declare -fx dummy
$ dummy
hi
$echo $dummy
$

Không phải việc tạo ra chức năng này, cũng không phải là bất cứ điều gì nó sẽ được chạy, là một phần của việc khai thác - nó chỉ là phương tiện mà việc khai thác được thực hiện. Vấn đề là nếu kẻ tấn công có thể cung cấp mã độc, đi trước một định nghĩa hàm tối thiểu và không quan trọng, trong một chuỗi văn bản được đưa vào một biến môi trường xuất khẩu, thì nó sẽ được thực thi khi bắt đầu một lớp con, đó là một sự kiện phổ biến trong nhiều kịch bản. Hơn nữa, nó sẽ được thực thi với các đặc quyền của tập lệnh.


17
Mặc dù câu trả lời được chấp nhận thực sự nói điều này nếu bạn đọc nó một cách cẩn thận, tôi thấy câu trả lời này thậm chí còn rõ ràng và hữu ích hơn khi hiểu rằng đó là sự đánh giá của định nghĩa (chứ không phải là thực thi chức năng) đó là vấn đề.
natevw

1
Tại sao ví dụ này có exportlệnh trong khi những người khác có env? tôi đã nghĩ rằng envđang được sử dụng để xác định các biến môi trường sẽ được gọi khi một bash shell khác được khởi chạy. sau đó nó hoạt động như thế nào vớiexport
Haris

Cho đến thời điểm này vẫn chưa có câu trả lời được chấp nhận. Có lẽ tôi sẽ đợi vài ngày nữa trước khi chấp nhận. Nhược điểm của câu trả lời này là nó không phá vỡ lệnh ban đầu, cũng không thảo luận về cách lấy từ lệnh ban đầu trong câu hỏi đến các lệnh trong câu trả lời này, cho thấy chúng giống hệt nhau. Ngoài ra nó là một lời giải thích tốt.
jippie

@ralph - cả hai envexportxuất định nghĩa môi trường để chúng có sẵn trong một nhánh con. Vấn đề thực sự là làm thế nào các định nghĩa được xuất này được nhập vào môi trường của một lớp con và cụ thể là trong cơ chế nhập định nghĩa hàm.
sdenham

1
@ralph - envchạy một lệnh với một số tùy chọn và biến môi trường được đặt. Lưu ý rằng trong các ví dụ câu hỏi ban đầu, envđặt xthành một chuỗi và gọi bash -cbằng lệnh để chạy. Nếu bạn làm như vậy env x='foo' vim, Vim sẽ khởi chạy và trong đó bạn có thể gọi ra shell / môi trường chứa !echo $xnó và nó sẽ in foo, nhưng nếu bạn thoát và sau đó echo $x, nó sẽ không được xác định, vì nó chỉ tồn tại khi vim đang chạy thông qua envlệnh. Các exportlệnh thay vì đặt các giá trị tồn tại lâu trong môi trường hiện tại để một subshell chạy sau sẽ sử dụng chúng.
Gary Fixler

72

Tôi đã viết điều này như một bản tóm tắt theo phong cách hướng dẫn về câu trả lời xuất sắc của Chris Down ở trên.


Trong bash bạn có thể có các biến shell như thế này

$ t="hi there"
$ echo $t
hi there
$

Theo mặc định, các biến này không được kế thừa bởi các tiến trình con.

$ bash
$ echo $t

$ exit

Nhưng nếu bạn đánh dấu chúng để xuất, bash sẽ đặt cờ có nghĩa là chúng sẽ đi vào môi trường của các quy trình con (mặc dù envptham số không được nhìn thấy nhiều, maintrong chương trình C của bạn có ba tham số: main(int argc, char *argv[], char *envp[])trong đó mảng con trỏ cuối cùng là một mảng của các biến shell với định nghĩa của chúng).

Vì vậy, hãy xuất khẩu tnhư sau:

$ echo $t
hi there
$ export t
$ bash
$ echo $t
hi there
$ exit

Trong khi ở trên tkhông được xác định trong lớp con, nó sẽ xuất hiện sau khi chúng tôi xuất nó (sử dụng export -n tnếu bạn muốn dừng xuất nó).

Nhưng các chức năng trong bash là một động vật khác nhau. Bạn tuyên bố chúng như thế này:

$ fn() { echo "test"; }

Và bây giờ bạn có thể gọi hàm bằng cách gọi nó như thể nó là một lệnh shell khác:

$ fn
test
$

Một lần nữa, nếu bạn sinh ra một mạng con, chức năng của chúng tôi không được xuất:

$ bash
$ fn
fn: command not found
$ exit

Chúng ta có thể xuất một hàm với export -f:

$ export -f fn
$ bash
$ fn
test
$ exit

Đây là phần khó khăn: một hàm xuất như fnđược chuyển đổi thành biến môi trường giống như xuất khẩu biến shell của chúng ta tở trên. Điều này không xảy ra khi fnlà một biến cục bộ, nhưng sau khi xuất chúng ta có thể thấy nó là một biến shell. Tuy nhiên, bạn cũng có thể có một biến shell thông thường (tức là không phải hàm) có cùng tên. bash phân biệt dựa trên nội dung của biến:

$ echo $fn

$ # See, nothing was there
$ export fn=regular
$ echo $fn
regular
$ 

Bây giờ chúng ta có thể sử dụng envđể hiển thị tất cả các biến shell được đánh dấu để xuất và cả hàm thông thường fnvà hàm fnhiển thị:

$ env
.
.
.
fn=regular
fn=() {  echo "test"
}
$

Một lớp vỏ con sẽ nhập cả hai định nghĩa: một là một biến thông thường và một là một hàm:

$ bash
$ echo $fn
regular
$ fn
test
$ exit

Bạn có thể định nghĩa fnnhư chúng tôi đã làm ở trên hoặc trực tiếp dưới dạng gán biến thông thường:

$ fn='() { echo "direct" ; }'

Lưu ý đây là một điều cao bất thường để làm! Thông thường chúng ta sẽ định nghĩa hàm fnnhư chúng ta đã làm ở trên với fn() {...}cú pháp. Nhưng vì bash xuất nó qua môi trường, chúng ta có thể "cắt ngắn" trực tiếp theo định nghĩa thông thường ở trên. Lưu ý rằng (đối chiếu với trực giác của bạn, có lẽ) điều này không dẫn đến một chức năng mới fncó sẵn trong trình bao hiện tại. Nhưng nếu bạn sinh ra một vỏ ** phụ **, thì nó sẽ.

Chúng ta hãy hủy xuất hàm fnvà giữ nguyên thông thường fn(như được hiển thị ở trên).

$ export -nf fn

Bây giờ hàm fnkhông còn được xuất, nhưng biến thông thường fnlà và nó chứa () { echo "direct" ; }trong đó.

Bây giờ khi một lớp con nhìn thấy một biến thông thường bắt đầu bằng ()nó sẽ hiểu phần còn lại là một định nghĩa hàm. Nhưng đây chỉ là khi một vỏ mới bắt đầu. Như chúng ta đã thấy ở trên, chỉ cần xác định một biến shell thông thường bắt đầu bằng ()không làm cho nó hoạt động như một hàm. Bạn phải bắt đầu một subshell.

Và bây giờ là lỗi "shellshock":

Như chúng ta vừa thấy, khi một shell mới ăn vào định nghĩa của một biến thông thường bắt đầu với ()nó sẽ diễn giải nó như là một hàm. Tuy nhiên, nếu có nhiều hơn được đưa ra sau dấu ngoặc đóng định nghĩa hàm, nó cũng thực thi bất cứ thứ gì có ở đó.

Đây là những yêu cầu, một lần nữa:

  1. Bash mới được sinh ra
  2. Một biến môi trường được tiêu hóa
  3. Biến môi trường này bắt đầu bằng "()" và sau đó chứa phần thân hàm bên trong dấu ngoặc, và sau đó có các lệnh sau đó

Trong trường hợp này, một bash dễ bị tổn thương sẽ thực thi các lệnh sau.

Thí dụ:

$ export ex='() { echo "function ex" ; }; echo "this is bad"; '
$ bash
this is bad
$ ex
function ex
$

Biến xuất thường xuyên exđược chuyển đến lớp con được hiểu là hàm exnhưng các lệnh trailing được thực thi ( this is bad) khi lớp con sinh ra.


Giải thích về bài kiểm tra một dòng trơn

Một phần mềm phổ biến để kiểm tra lỗ hổng Shellshock là phần được trích dẫn trong câu hỏi của @ jippie:

env x='() { :;}; echo vulnerable' bash -c "echo this is a test"

Đây là một sự cố: đầu tiên :trong bash chỉ là một tốc ký true. true:cả hai đều đánh giá (bạn đoán nó) đúng, trong bash:

$ if true; then echo yes; fi
yes
$ if :; then echo yes; fi
yes
$

Thứ hai, envlệnh (cũng được tích hợp vào bash) in các biến môi trường (như chúng ta đã thấy ở trên) nhưng cũng có thể được sử dụng để chạy một lệnh với một biến xuất (hoặc biến) được cung cấp cho lệnh đó và bash -cchạy một lệnh từ lệnh đó dòng lệnh:

$ bash -c 'echo hi'
hi
$ bash -c 'echo $t'

$ env t=exported bash -c 'echo $t'
exported
$

Vì vậy, khâu tất cả các công cụ này lại với nhau, chúng ta có thể chạy bash như một lệnh, cung cấp cho nó một số thứ giả để làm (như bash -c echo this is a test) và xuất một biến bắt đầu bằng ()để lớp con sẽ hiểu nó là một hàm. Nếu shellshock có mặt, nó cũng sẽ ngay lập tức thực hiện bất kỳ lệnh trailing nào trong subshell. Vì hàm chúng tôi chuyển không liên quan đến chúng tôi (nhưng phải phân tích cú pháp!), Chúng tôi sử dụng hàm hợp lệ ngắn nhất có thể tưởng tượng:

$ f() { :;}
$ f
$ 

Hàm fở đây chỉ thực thi :lệnh, trả về true và thoát. Bây giờ hãy thêm vào lệnh "ác" đó và xuất một biến thông thường sang một mạng con và bạn thắng. Đây là một lần nữa:

$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"

Vì vậy, xđược xuất như một biến thông thường với một hàm hợp lệ đơn giản được echo vulnerablexử lý đến cuối. Điều này được truyền cho bash và bash diễn giải xnhư là một hàm (mà chúng ta không quan tâm) sau đó có thể thực thi echo vulnerablenếu shellshock có mặt.

Chúng tôi có thể rút ngắn một lớp lót một chút bằng cách xóa this is a testtin nhắn:

$ env x='() { :;}; echo vulnerable' bash -c :

Điều này không làm phiền với this is a testnhưng chạy :lệnh im lặng một lần nữa. (Nếu bạn rời khỏi -c :thì bạn ngồi trong subshell và phải thoát bằng tay.) Có lẽ phiên bản thân thiện với người dùng nhất sẽ là phiên bản này:

$ env x='() { :;}; echo vulnerable' bash -c "echo If you see the word vulnerable above, you are vulnerable to shellshock"

12
Giải thích tốt đẹp. Câu hỏi này đang nhận được rất nhiều lượt xem (có lẽ không phải ai cũng thành thạo bash như những người khác) và tôi tin rằng chưa có ai dành vài lời cho những gì { :;};thực sự nói. Đó sẽ là một bổ sung tốt đẹp cho câu trả lời của bạn theo ý kiến ​​của tôi. Có thể giải thích làm thế nào bạn nhận được từ ví dụ của bạn đến lệnh ban đầu trong câu hỏi?
jippie

20

Nếu bạn có thể cung cấp các biến môi trường tùy ý cho một chương trình, bạn có thể khiến nó làm bất cứ điều gì bằng cách tải nó vào các thư viện bạn chọn. Trong hầu hết các trường hợp, điều này không được coi là một lỗ hổng trong chương trình nhận các biến môi trường đó, mà là trong cơ chế mà người ngoài có thể cung cấp các biến môi trường tùy ý.

Tuy nhiên CVE-2014-6271 thì khác.

Không có gì sai khi có dữ liệu không đáng tin cậy trong một biến môi trường. Người ta chỉ cần đảm bảo rằng nó không được đặt vào bất kỳ biến môi trường nào có thể sửa đổi hành vi của chương trình. Tóm tắt hơn một chút, đối với một lệnh gọi cụ thể, bạn có thể tạo một danh sách trắng các tên biến môi trường, được phép được chỉ định trực tiếp bởi người ngoài.

Một ví dụ đã được đưa ra trong bối cảnh CVE-2014-6271 là các tập lệnh được sử dụng để phân tích cú pháp logfiles. Những người có thể có một nhu cầu rất chính đáng để truyền dữ liệu không đáng tin cậy xung quanh trong các biến môi trường. Tất nhiên, tên của một biến môi trường như vậy được chọn sao cho nó không có bất kỳ ảnh hưởng bất lợi nào.

Nhưng đây là những gì là xấu về lỗ hổng bash đặc biệt này. Nó có thể được khai thác thông qua bất kỳ tên biến. Nếu bạn tạo một biến môi trường được gọi GET_REQUEST_TO_BE_PROCESSED_BY_MY_SCRIPT, bạn sẽ không mong đợi bất kỳ chương trình nào khác ngoài tập lệnh của riêng bạn diễn giải nội dung của biến môi trường đó. Nhưng bằng cách khai thác lỗi bash này, mọi biến môi trường đơn lẻ trở thành một vectơ tấn công.

Lưu ý rằng điều này không có nghĩa là tên của các biến môi trường được dự kiến ​​là bí mật. Biết tên của các biến môi trường có liên quan sẽ không khiến cuộc tấn công trở nên dễ dàng hơn.

Nếu program1các cuộc gọi program2lần lượt gọi program3, thì program1có thể chuyển dữ liệu program3qua các biến môi trường. Mỗi chương trình có một danh sách cụ thể các biến môi trường mà nó thiết lập và một danh sách cụ thể mà nó hoạt động. Nếu bạn chọn một tên không được program2, bạn có thể truyền dữ liệu từ program1để program3không phải lo lắng về vấn đề này có bất kỳ ảnh hưởng bất lợi trên program2.

Kẻ tấn công biết tên chính xác của các biến được xuất bởi program1và tên của các biến được giải thích bởi program2không thể khai thác kiến ​​thức này để sửa đổi hành vi của 'chương trình 2` nếu không có sự trùng lặp giữa bộ tên.

Nhưng điều này đã bị hỏng nếu program2là một bashtập lệnh, bởi vì lỗi này bashsẽ diễn giải mọi biến môi trường là mã.


1
"Mỗi biến môi trường đơn lẻ trở thành một vectơ tấn công" - đó là phần tôi bị thiếu. Cảm ơn.
wrschneider

9

Nó được giải thích trong bài viết bạn liên kết ...

bạn có thể tạo các biến môi trường với các giá trị được chế tạo đặc biệt trước khi gọi bash shell. Các biến này có thể chứa mã, được thực thi ngay khi shell được gọi.

Điều đó có nghĩa là bash được gọi với -c "echo this is a test"thực thi mã trong các dấu ngoặc đơn khi nó được gọi.

Bash có các hàm, mặc dù trong một triển khai có phần hạn chế và có thể đặt các hàm bash này vào các biến môi trường. Lỗ hổng này được kích hoạt khi thêm mã bổ sung vào cuối các định nghĩa hàm này (bên trong biến enivronment).

Có nghĩa là ví dụ mã bạn đã đăng khai thác thực tế là bash được gọi không dừng đánh giá chuỗi này sau khi thực hiện chuyển nhượng. Một sự phân công chức năng trong trường hợp này.

Điều thực sự đặc biệt về đoạn mã bạn đã đăng, như tôi hiểu, là bằng cách sử dụng định nghĩa hàm trước mã chúng ta muốn thực thi, một số cơ chế bảo mật có thể bị phá vỡ.

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.