11.11.2 Encryption và. Chức năng nén
Table 11.17. Encryption Functions Bảng 11,17. Chức năng mã hóa
Name Tên | Description Mô tả |
---|---|
AES_DECRYPT() | Decrypt using AES Giải mã bằng cách sử dụng AES |
AES_ENCRYPT() | Encrypt using AES Mã hóa AES bằng cách sử dụng |
COMPRESS() (v4.1.1) COMPRESS() (v4.1.1) | Return result as a binary string Quay trở lại kết quả như là một chuỗi nhị phân |
DECODE() | Decodes a string encrypted using ENCODE() Giải mã một chuỗi mã hóa bằng cách sử dụng mã hóa () |
DES_DECRYPT() | Decrypt a string Giải mã một chuỗi |
DES_ENCRYPT() | Encrypt a string Mã hóa một chuỗi |
ENCODE() | Encode a string Mã hóa một chuỗi |
ENCRYPT() | Encrypt a string Mã hóa một chuỗi |
MD5() | Calculate MD5 checksum Tính toán MD5 checksum |
OLD_PASSWORD() (v4.1) OLD_PASSWORD() (v4.1) | Return the value of the old (pre-4.1) implementation of PASSWORD Quay trở lại giá trị của (cũ trước 4,1) thực hiện các PASSWORD |
PASSWORD() | Calculate and return a password string Tính toán và trả về một chuỗi mật khẩu |
SHA1() , SHA() SHA1() , SHA() | Calculate an SHA-1 160-bit checksum Tính toán một SHA-1 160-bit checksum |
UNCOMPRESS() (v4.1.1) UNCOMPRESS() (v4.1.1) | Uncompress a string compressed Giải nén một chuỗi nén |
UNCOMPRESSED_LENGTH() (v4.1.1) UNCOMPRESSED_LENGTH() (v4.1.1) | Return the length of a string before compression Trở về độ dài của một chuỗi trước khi nén |
Note Ghi
The encryption and compression functions return binary strings. Các chức năng mã hóa và nén trở lại chuỗi nhị phân. For many of these functions, the result might contain arbitrary byte values. Đối với nhiều người trong số các chức năng này, kết quả có thể chứa các giá trị byte tùy ý. If you want to store these results, use a column with a VARBINARY
or BLOB
binary string data type. This will avoid potential problems with trailing space removal or character set conversion that would change data values, such as may occur if you use a nonbinary string data type ( CHAR
, VARCHAR
, TEXT
). Nếu bạn muốn lưu trữ các kết quả này, sử dụng một cột với một VARBINARY
hoặc BLOB
chuỗi định dạng dữ liệu nhị phân. Điều này sẽ tránh những vấn đề tiềm năng với dấu loại bỏ hoặc chuyển đổi không gian bộ ký tự mà có thể thay đổi giá trị dữ liệu, chẳng hạn như có thể xảy ra nếu bạn sử dụng một chuỗi nonbinary loại dữ liệu ( CHAR
, VARCHAR
, TEXT
).
Note Ghi
Exploits for the MD5 and SHA-1 algorithms have become known. You may wish to consider using one of the other encryption functions described in this section instead. Khai thác đối với MD5 và SHA-1 thuật toán đã trở nên nổi tiếng. Bạn có thể xem xét sử dụng một trong các chức năng mã hóa khác được mô tả trong phần này để thay thế.
AES_DECRYPT(
crypt_str
,key_str
)This function allows decryption of data using the official AES (Advanced Encryption Standard) algorithm. Chức năng này cho phép giải mã dữ liệu bằng cách sử dụng AES chính thức (Advanced Encryption Standard) thuật toán. For more information, see the description of
AES_ENCRYPT()
. Để biết thêm thông tin, xem mô tả củaAES_ENCRYPT()
.-
AES_ENCRYPT()
andAES_DECRYPT()
allow encryption and decryption of data using the official AES (Advanced Encryption Standard) algorithm, previously known as “ Rijndael. ” Encoding with a 128-bit key length is used, but you can extend it up to 256 bits by modifying the source.AES_ENCRYPT()
vàAES_DECRYPT()
cho phép mã hóa và giải mã dữ liệu bằng cách sử dụng chính thức AES (Advanced Encryption Standard) thuật toán, trước đây được gọi là "Rijndael chiều dài." Encoding với khóa 128-bit được sử dụng, nhưng bạn có thể mở rộng nó lên đến 256 bit bằng cách sửa đổi mã nguồn. We chose 128 bits because it is much faster and it is secure enough for most purposes. Chúng tôi chọn 128 bit bởi vì nó là nhanh hơn nhiều và nó là an toàn đủ cho hầu hết các mục đích.AES_ENCRYPT()
encrypts a string and returns a binary string.AES_DECRYPT()
decrypts the encrypted string and returns the original string.AES_ENCRYPT()
mã hóa một chuỗi và trả về một chuỗi nhị phân.AES_DECRYPT()
giải mã chuỗi mã hóa và trả về chuỗi ban đầu. The input arguments may be any length. Các đối số đầu vào có thể là bất kỳ chiều dài. If either argument isNULL
, the result of this function is alsoNULL
. Nếu đối số, hoặc làNULL
, kết quả của chức năng này cũng làNULL
.Because AES is a block-level algorithm, padding is used to encode uneven length strings and so the result string length may be calculated using this formula: Do AES là một cấp thuật toán khối, đệm được sử dụng để mã hóa các chuỗi có chiều dài không đồng đều và do đó chiều dài chuỗi kết quả có thể được tính bằng cách sử dụng công thức này:
16 * (trunc(
string_length
/ 16) + 1) 16 * (hàm TRUNC (string_length
/ 16) + 1)If
AES_DECRYPT()
detects invalid data or incorrect padding, it returnsNULL
. NếuAES_DECRYPT()
phát hiện dữ liệu không hợp lệ hoặc đệm không đúng, nó sẽ trả vềNULL
. However, it is possible forAES_DECRYPT()
to return a non-NULL
value (possibly garbage) if the input data or the key is invalid. Tuy nhiên, có thể choAES_DECRYPT()
để trở về một khôngNULL
giá trị (có thể là rác) nếu dữ liệu đầu vào hoặc phím không hợp lệ.You can use the AES functions to store data in an encrypted form by modifying your queries: Bạn có thể sử dụng chức năng lưu trữ dữ liệu AES trong một hình thức được mã hóa bằng cách sửa đổi các truy vấn của bạn:
INSERT INTO t VALUES (1,AES_ENCRYPT('text','password')); INSERT INTO t giá trị (1, AES_ENCRYPT ('text', 'mật khẩu'));
AES_ENCRYPT()
andAES_DECRYPT()
can be considered the most cryptographically secure encryption functions currently available in MySQL.AES_ENCRYPT()
vàAES_DECRYPT()
có thể được coi là mã hóa hầu hết các chức năng mã hóa an toàn hiện đang có sẵn trong MySQL. COMPRESS(
string_to_compress
)Compresses a string and returns the result as a binary string. Nén một chuỗi và trả về kết quả như là một chuỗi nhị phân. This function requires MySQL to have been compiled with a compression library such as
zlib
. Otherwise, the return value is alwaysNULL
. Chức năng này đòi hỏi MySQL đã được biên dịch với một thư viện nén nhưzlib
. Nếu không, giá trị trả lại luôn luôn làNULL
. The compressed string can be uncompressed withUNCOMPRESS()
. Chuỗi nén có thể được nén vớiUNCOMPRESS()
.mysql>
SELECT LENGTH(COMPRESS(REPEAT('a',1000)));
mysql>SELECT LENGTH(COMPRESS(REPEAT('a',1000)));
-> 21 -> 21
mysql>SELECT LENGTH(COMPRESS(''));
mysql>SELECT LENGTH(COMPRESS(''));
-> 0 -> 0
mysql>SELECT LENGTH(COMPRESS('a'));
mysql>SELECT LENGTH(COMPRESS('a'));
-> 13 -> 13
mysql>SELECT LENGTH(COMPRESS(REPEAT('a',16)));
mysql>SELECT LENGTH(COMPRESS(REPEAT('a',16)));
-> 15 -> 15The compressed string contents are stored the following way: Nội dung chuỗi nén được lưu trữ theo cách sau:
Empty strings are stored as empty strings. chuỗi rỗng được lưu trữ như là chuỗi sản phẩm nào.
Nonempty strings are stored as a four-byte length of the uncompressed string (low byte first), followed by the compressed string. chuỗi không rỗng được lưu trữ như là một-byte chiều dài bốn của chuỗi không nén (thấp byte đầu tiên), tiếp theo là chuỗi nén. If the string ends with space, an extra “
.
” character is added to avoid problems with endspace trimming should the result be stored in aCHAR
orVARCHAR
column. Nếu chuỗi kết thúc với không gian, một "thêm.
"nhân vật được thêm vào để tránh vấn đề với endspace cắt tỉa kết quả cần được lưu giữ trong mộtCHAR
hayVARCHAR
cột. (However, use of nonbinary string data types such asCHAR
orVARCHAR
to store compressed strings is not recommended anyway because character set conversion may occur. Use aVARBINARY
orBLOB
binary string column instead.) (Tuy nhiên, việc sử dụng chuỗi nonbinary loại dữ liệu nhưCHAR
hayVARCHAR
để lưu trữ nén dây không được khuyến cáo anyway vì bộ chuyển đổi có thể xảy ra một ký tự. Sử dụngVARBINARY
hoặcBLOB
cột chuỗi nhị phân thay thế.)
DECODE(
crypt_str
,pass_str
)Decrypts the encrypted string
crypt_str
usingpass_str
as the password.crypt_str
should be a string returned fromENCODE()
. Giải mã chuỗi mã hóacrypt_str
sử dụngpass_str
như mật khẩu.crypt_str
phải là một chuỗi trở về từENCODE()
.-
Encrypt
str
usingpass_str
as the password. Mã hóastr
bằng cách sử dụngpass_str
như mật khẩu. To decrypt the result, useDECODE()
. Để giải mã kết quả, sử dụngDECODE()
.The result is a binary string of the same length as
str
. Kết quả là một chuỗi nhị phân của độ dài tương tự nhưstr
.The strength of the encryption is based on how good the random generator is. Sức mạnh của mật mã dựa trên cách thức tốt các máy phát điện là ngẫu nhiên. It should suffice for short strings. Nó sẽ đủ cho các chuỗi ngắn.
DES_DECRYPT(
crypt_str
[,key_str
])Decrypts a string encrypted with
DES_ENCRYPT()
. Giải mã một chuỗi mã hóa vớiDES_ENCRYPT()
. If an error occurs, this function returnsNULL
. Nếu lỗi xảy ra, điều này hàm trả vềNULL
.This function works only if MySQL has been configured with SSL support. Chức năng này chỉ hoạt động nếu MySQL đã được cấu hình hỗ trợ SSL. See Section 5.5.6, “Using SSL for Secure Connections” . Xem Phần 5.5.6, "Sử dụng SSL cho kết nối an toàn" .
If no
key_str
argument is given,DES_DECRYPT()
examines the first byte of the encrypted string to determine the DES key number that was used to encrypt the original string, and then reads the key from the DES key file to decrypt the message. Nếu không cókey_str
đối số được đưa ra,DES_DECRYPT()
kiểm tra các byte đầu tiên của chuỗi được mã hóa để xác định các phím số DES đã được sử dụng để mã hóa các chuỗi ban đầu, và sau đó đọc chính từ các tập tin quan trọng để giải mã DES tin. For this to work, the user must have theSUPER
privilege. Để làm việc này, người sử dụng phải có cácSUPER
đặc quyền. The key file can be specified with the--des-key-file
server option. Các tập tin quan trọng có thể được chỉ định với các--des-key-file
tùy chọn server.If you pass this function a
key_str
argument, that string is used as the key for decrypting the message. Nếu bạn vượt qua chức năng này mộtkey_str
đối số, chuỗi ký tự được sử dụng như là chìa khóa để giải mã thông điệp.If the
crypt_str
argument does not appear to be an encrypted string, MySQL returns the givencrypt_str
. Nếucrypt_str
đối số không xuất hiện cho được một chuỗi mã hóa, MySQL sẽ trả về chocrypt_str
.DES_ENCRYPT(
str
[,{key_num
|key_str
}])Encrypts the string with the given key using the Triple-DES algorithm. Mã hóa chuỗi với phím được sử dụng thuật toán Triple-DES.
This function works only if MySQL has been configured with SSL support. Chức năng này chỉ hoạt động nếu MySQL đã được cấu hình hỗ trợ SSL. See Section 5.5.6, “Using SSL for Secure Connections” . Xem Phần 5.5.6, "Sử dụng SSL cho kết nối an toàn" .
The encryption key to use is chosen based on the second argument to
DES_ENCRYPT()
, if one was given. Các mã hóa khóa để sử dụng là lựa chọn dựa trên các tham số thứ hai đểDES_ENCRYPT()
, nếu một chủng. With no argument, the first key from the DES key file is used. Với lập luận không có, phím đầu tiên từ tập tin quan trọng DES được sử dụng. With akey_num
argument, the given key number (0 to 9) from the DES key file is used. Với mộtkey_num
đối số, các phím số nhất định (0-9) từ các tập tin quan trọng DES được sử dụng. With akey_str
argument, the given key string is used to encryptstr
. Với mộtkey_str
đối số, chìa khóa cho chuỗi được sử dụng để mã hóastr
.The key file can be specified with the
--des-key-file
server option. Các tập tin quan trọng có thể được chỉ định với các--des-key-file
tùy chọn server.The return string is a binary string where the first character is
CHAR(128 |
. Chuỗi trả về là một chuỗi nhị phân, nơi ký tự đầu tiên làkey_num
)CHAR(128 |
. If an error occurs,key_num
)DES_ENCRYPT()
returnsNULL
. Nếu lỗi xảy ra,DES_ENCRYPT()
trả vềNULL
.The 128 is added to make it easier to recognize an encrypted key. 128 được thêm vào để làm cho nó dễ dàng hơn để nhận ra một khoá mật mã. If you use a string key,
key_num
is 127. Nếu bạn sử dụng một chìa khóa dây,key_num
là 127.The string length for the result is given by this formula: Chiều dài chuỗi cho kết quả được cho bởi công thức này:
new_len
=orig_len
+ (8 - (orig_len
% 8)) + 1new_len
=orig_len
+ (8 - (orig_len
% 8)) + 1Each line in the DES key file has the following format: Mỗi dòng trong tập tin quan trọng DES có định dạng sau:
key_num des_key_str
key_num des_key_str
Each
key_num
value must be a number in the range from0
to9
. Mỗikey_num
giá trị phải là một số trong khoảng từ0
đến9
. Lines in the file may be in any order.des_key_str
is the string that is used to encrypt the message. Dòng trong tập tin có thể được theo thứ tự bất kỳ.des_key_str
là một chuỗi được sử dụng để mã hóa thông điệp. There should be at least one space between the number and the key. Nên có ít nhất một khoảng trống giữa số lượng và phím. The first key is the default key that is used if you do not specify any key argument toDES_ENCRYPT()
. Chìa khóa đầu tiên là phím mặc định được sử dụng nếu bạn không chỉ định bất kỳ đối số chính đểDES_ENCRYPT()
.You can tell MySQL to read new key values from the key file with the
FLUSH DES_KEY_FILE
statement. Bạn có thể cho biết MySQL để đọc chính những giá trị mới từ các tập tin quan trọng vớiFLUSH DES_KEY_FILE
tuyên bố. This requires theRELOAD
privilege. Điều này đòi hỏiRELOAD
đặc quyền.One benefit of having a set of default keys is that it gives applications a way to check for the existence of encrypted column values, without giving the end user the right to decrypt those values. Một lợi ích của việc có một bộ các phím mặc định là nó cho phép các ứng dụng một cách để kiểm tra sự tồn tại của các giá trị cột mã hóa, mà không cho người dùng cuối quyền để giải mã các giá trị.
mysql>
SELECT customer_address FROM customer_table
> MysqlSELECT customer_address FROM customer_table
>WHERE crypted_credit_card = DES_ENCRYPT('credit_card_number');
>WHERE crypted_credit_card = DES_ENCRYPT('credit_card_number');
-
Encrypts
str
using the Unixcrypt()
system call and returns a binary string. Mã hóastr
bằng cách sử dụng Unixcrypt()
hệ thống gọi và trả về một chuỗi nhị phân. Thesalt
argument should be a string with at least two characters. Cácsalt
đối số phải là một chuỗi với ít nhất hai nhân vật. If nosalt
argument is given, a random value is used. Nếu không cósalt
đối số được đưa ra, một giá trị ngẫu nhiên được sử dụng.mysql>
SELECT ENCRYPT('hello');
mysql>SELECT ENCRYPT('hello');
-> 'VxuFAJXVARROc' -> 'VxuFAJXVARROc'ENCRYPT()
ignores all but the first eight characters ofstr
, at least on some systems.ENCRYPT()
sẽ bỏ qua tất cả, nhưng các ký tự đầu tiên tám củastr
, ít nhất là trên một số hệ thống. This behavior is determined by the implementation of the underlyingcrypt()
system call. Hành vi này được xác định bởi việc thực hiện cơ bảncrypt()
hệ thống gọi.The use of
ENCRYPT()
with multi-byte character sets other thanutf8
is not recommended because the system call expects a string terminated by a zero byte. Việc sử dụngENCRYPT()
với nhân vật đa-byte bộ khác hơn làutf8
không được khuyến khích bởi vì hệ thống sẽ gọi một chuỗi kết thúc bởi một byte số không.If
crypt()
is not available on your system (as is the case with Windows),ENCRYPT()
always returnsNULL
. Nếucrypt()
là không có sẵn trên hệ thống của bạn (như là trường hợp với Windows),ENCRYPT()
luôn trả vềNULL
. -
Calculates an MD5 128-bit checksum for the string. Tính toán MD5 checksum 128-bit cho chuỗi. The value is returned as a binary string of 32 hex digits, or
NULL
if the argument wasNULL
. Giá trị được trả về như là một chuỗi nhị phân của 32 chữ số hex, hoặcNULL
nếu đối số làNULL
. The return value can, for example, be used as a hash key. Các giá trị trả về có thể, ví dụ, được sử dụng như một chìa khóa băm.mysql>
SELECT MD5('testing');
mysql>SELECT MD5('testing');
-> 'ae2b1fca515949e5d54fb22b8ed95575' -> 'Ae2b1fca515949e5d54fb22b8ed95575'This is the “ RSA Data Security, Inc. MD5 Message-Digest Algorithm. ” Đây là "RSA Data Security, Inc MD5 Message-Digest Algorithm".
If you want to convert the value to uppercase, see the description of binary string conversion given in the entry for the
BINARY
operator in Section 11.9, “Cast Functions and Operators” . Nếu bạn muốn chuyển đổi giá trị thành chữ hoa, xem mô tả về chuyển đổi chuỗi nhị phân được đưa ra trong mục nhập choBINARY
điều hành trong mục 11,9, "Diễn viên Chức năng và sử dụng" .See the note regarding the MD5 algorithm at the beginning this section. Xem các lưu ý về thuật toán MD5 ở phần này bắt đầu.
-
OLD_PASSWORD()
was added to MySQL when the implementation ofPASSWORD()
was changed to improve security.OLD_PASSWORD()
returns the value of the old (pre-4.1) implementation ofPASSWORD()
as a binary string, and is intended to permit you to reset passwords for any pre-4.1 clients that need to connect to your version 5.1 MySQL server without locking them out.OLD_PASSWORD()
đã được MySQL khi thực hiện cácPASSWORD()
đã được thay đổi để cải thiện an ninh.OLD_PASSWORD()
trả về giá trị của (cũ trước 4,1) thực hiệnPASSWORD()
như là một chuỗi nhị phân, và được thiết kế để cho phép bạn để thiết lập lại mật khẩu cho bất kỳ tiền 4,1 khách hàng có nhu cầu để kết nối với phiên bản của bạn 5,1 MySQL server mà không khóa chúng ra. See Section 5.3.2.3, “Password Hashing in MySQL” . Xem Phần 5.3.2.3, "Mật khẩu băm trong" MySQL . -
Calculates and returns a password string from the plaintext password
str
and returns a binary string, orNULL
if the argument wasNULL
. Tính toán và trả về một chuỗi mật khẩu từ mật khẩu chữ thôstr
và trả về một chuỗi nhị phân, hoặcNULL
nếu đối số làNULL
. This is the function that is used for encrypting MySQL passwords for storage in thePassword
column of theuser
grant table. Đây là chức năng được sử dụng để mã hóa mật khẩu MySQL cho việc lưu trữ trong cácPassword
cột củauser
bảng cấp.mysql>
SELECT PASSWORD('badpwd');
mysql>SELECT PASSWORD('badpwd');
-> '*AAB3E285149C0135D51A520E1940DD3263DC008C' -> '* AAB3E285149C0135D51A520E1940DD3263DC008C'PASSWORD()
encryption is one-way (not reversible).PASSWORD()
là mã hóa một chiều (không thuận nghịch).PASSWORD()
does not perform password encryption in the same way that Unix passwords are encrypted.PASSWORD()
không thực hiện mã hóa mật khẩu trong cùng một cách mà các mật khẩu được mã hóa Unix. SeeENCRYPT()
. XemENCRYPT()
.Note Ghi
The
PASSWORD()
function is used by the authentication system in MySQL Server; you should not use it in your own applications. CácPASSWORD()
chức năng được sử dụng bởi hệ thống xác thực trong MySQL Server, bạn không nên sử dụng nó trong các ứng dụng của riêng bạn. For that purpose, considerMD5()
orSHA1()
instead. Cho mục đích đó, hãy xem xétMD5()
hoặcSHA1()
để thay thế. Also see RFC 2195, section 2 (Challenge-Response Authentication Mechanism (CRAM)) , for more information about handling passwords and authentication securely in your applications. Xem thêm RFC 2195, tiết đoạn 2 (Challenge-Response Cơ chế xác thực (Cram)) , cho biết thêm thông tin về xử lý mật khẩu và chứng thực an toàn trong các ứng dụng của bạn. SHA1(
,str
)SHA(
str
)SHA1(
,str
)SHA(
str
)Calculates an SHA-1 160-bit checksum for the string, as described in RFC 3174 (Secure Hash Algorithm). Tính toán SHA-1 160-bit checksum cho chuỗi, như mô tả trong RFC 3.174 (Secure Hash Algorithm). The value is returned as a binary string of 40 hex digits, or
NULL
if the argument wasNULL
. Giá trị được trả về như là một chuỗi nhị phân của 40 chữ số hex, hoặcNULL
nếu đối số làNULL
. One of the possible uses for this function is as a hash key. Một trong những sử dụng chức năng này có thể cho là như là một chìa khóa hash. You can also use it as a cryptographic function for storing passwords.SHA()
is synonymous withSHA1()
. Bạn cũng có thể sử dụng nó như một mật mã cho chức năng lưu trữ mật khẩu.SHA()
là đồng nghĩa vớiSHA1()
.mysql>
SELECT SHA1('abc');
> MysqlSELECT SHA1('abc');
-> 'a9993e364706816aba3e25717850c26c9cd0d89d' -> 'A9993e364706816aba3e25717850c26c9cd0d89d'SHA1()
can be considered a cryptographically more secure equivalent ofMD5()
.SHA1()
có thể được coi là an toàn hơn mã hóa tương đương vớiMD5()
. However, see the note regarding the MD5 and SHA-1 algorithms at the beginning this section. Tuy nhiên, xem các lưu ý về MD5 và SHA-1 thuật toán ở phần này bắt đầu.UNCOMPRESS(
string_to_uncompress
)Uncompresses a string compressed by the
COMPRESS()
function. Uncompresses một chuỗi nén củaCOMPRESS()
chức năng. If the argument is not a compressed value, the result isNULL
. Nếu các đối số không phải là một giá trị nén, kết quả làNULL
. This function requires MySQL to have been compiled with a compression library such aszlib
. Chức năng này đòi hỏi MySQL đã được biên dịch với một thư viện nén nhưzlib
. Otherwise, the return value is alwaysNULL
. Nếu không, giá trị trả lại luôn luôn làNULL
.mysql>
SELECT UNCOMPRESS(COMPRESS('any string'));
mysql>SELECT UNCOMPRESS(COMPRESS('any string'));
-> 'any string' -> 'Chuỗi bất kỳ'
mysql>SELECT UNCOMPRESS('any string');
mysql>SELECT UNCOMPRESS('any string');
-> NULL -> NULLUNCOMPRESSED_LENGTH(
compressed_string
)Returns the length that the compressed string had before being compressed. Trả về độ dài chuỗi rằng đã có trước khi được nén nén.
mysql>
SELECT UNCOMPRESSED_LENGTH(COMPRESS(REPEAT('a',30)));
mysql>SELECT UNCOMPRESSED_LENGTH(COMPRESS(REPEAT('a',30)));
-> 30 -> 30
Không có nhận xét nào:
Đăng nhận xét