Chuẩn hóa và xác thực dữ liệu với WordPress

Việc bảo mật phù hợp là rất quan trọng để giữ cho website hoặc theme hoặc plugin người dùng được an toàn. Một phần của việc đó có nghĩa là xác nhận và chuẩn hóa dữ liệu phù hợp. Trong bài viết này, chúng ta sẽ xem lý do tại sao việc này lại quan trọng, những gì cần phải làm và WordPress đề xuất những hàm trợ giúp nào.

Vì dường như có nhiều cách hiểu khác nhau về ý nghĩa của các thuật ngữ ‘validation'(xác nhận), ‘escaping’ và ‘sanitization’, trước tiên tôi sẽ làm rõ ý của tôi trong bài viết này:

  • Validation (xác nhận) – Đây là những kiểm tra được chạy để đảm bảo dữ liệu bạn  là phù hợp. Chẳng hạn, email là email, date là date và number(hoặc được chuyển đổi) một là integer(số nguyên).
  • Sanitization / Escaping – Đây là các filter (bộ lọc) được áp dụng cho dữ liệu để làm cho dữ liệu ‘an toàn’ trong tình huống cụ thể. Chẳng hạn, để hiển thị code HTML trong textarea, cần phải thay thế tất cả các thẻ HTML bằng các thực thể tương đương với chúng

Khi dữ liệu được xem xét trong một số tình huống(giả sử trong tài liệu HTML) – dữ liệu đó có thể bị hiểu sai là code cho môi trường đó(ví dụ code HTML). Nếu dữ liệu đó chứa code độc hại, sau đó sử dụng dữ liệu đó mà không sanitization nó, có nghĩa là code đó sẽ được thực thi. Code thậm chí không nhất thiết phải có hại để gây ra các hiệu ứng không mong muốn. Công việc sanitization là đảm bảo rằng bất kỳ code nào trong dữ liệu không được thông dịch thành code – nếu không, bạn có thể nhận kết quả như trường học của Bobby Tables.

Một ví dụ có vẻ vô hại là một trường tìm kiếm có sẵn với cụm từ được tìm kiếm, sử dụng unescaped $_GET['s']:

1
2
3
4
<form method="get" id="searchform" action="<?php echo esc_url( home_url( '/' ) ); ?>">
  <input type="text" class="field" name="s" id="s" value="<?php echo $_GET['s']; ?>"/>
    <input type="submit" class="submit" name="submit" id="searchsubmit" value="Search" />
</form>

Điều này tạo ra một lỗ hổng có thể cho phép javascript được chèn vào, ví dụ như lừa ai đó truy cập http://yoursite.com?s=/>< script>alert('Injected javascript')</script> Thuật ngữ tìm kiếm ‘escape’ ra khỏi thuộc tính của giá trị và phần sau của dữ liệu được hiểu là code và được thực thi. Để ngăn chặn điều này, WordPress đề xuất get_search_query trả về truy vấn tìm kiếm đã được sanitize. Mặc dù đây là một ví dụ ‘vô hại’, script được chèn có thể nguy hại hơn nhiều và mức cao nhất là sẽ ‘phá vỡ’ form nếu cụm từ tìm kiếm chứa dấu ngoặc kép.

Làm thế nào code độc này(hoặc nói cách khác) có thể tìm được đường vào website của bạn không phải là mối quan tâm ở đây – quan trọng hơn là ngăn nó thực thi. Chúng tôi cũng không đưa ra các giả định về bản chất của code không mong muốn này hoặc ý định của nó – có thể nó chỉ đơn giản là lỗi phía người dùng. Điều này đưa tôi đến quy tắc số 1 …

Đó là một câu châm ngôn phổ biến được sử dụng liên quan đến sanitization dữ liệu và đó là một câu châm ngôn hay. Ý tưởng là bạn không nên cho rằng bất kỳ dữ liệu nào được người dùng nhập vào đều an toàn. Bạn cũng không nên cho rằng dữ liệu bạn đã truy xuất từ cơ sở dữ liệu là an toàn – ngay cả khi bạn đã khiến cho nó ‘an toàn’ trước khi chèn nó vào đó. Trong thực tế, liệu dữ liệu có thể được coi là “an toàn” khi không trong tình huống cụ thể thì xem như vô nghĩa. Đôi khi cùng một dữ liệu có thể được sử dụng trong nhiều tình huống trên cùng một trang. Ví dụ, title có thể chứa dấu ngoặc đơn hoặc dấu ngoặc kép một cách an toàn nếu ở bên trong thẻ header – nhưng sẽ gây ra sự cố nếu được sử dụng(unescaped) bên trong thuộc tính title của link tag. Vì vậy, thật vô nghĩa khi làm ‘an toàn’ dữ liệu lúc thêm nó vào cơ sở dữ liệu, vì thường không thể làm cho dữ liệu an toàn cho tất cả các tình huống cùng lúc. (Tất nhiên dữ liệu cần được đảm bảo an toàn khi thêm vào cơ sở dữ liệu – nhưng chúng ta sẽ nói đến sau).

Ngay cả khi bạn chỉ có ý định sử dụng dữ liệu đó trong một tình huống cụ thể, như trong một form, việc sanitization dữ liệu khi ghi vào cơ sở dữ liệu là vô nghĩa vì theo Quy tắc số 1, bạn không thể tin rằng nó vẫn còn an toàn khi bạn lấy nó ra lại.

Đây là câu châm ngôn về thủ tục bắt đầu khi nào bạn nên xác thực dữ liệu và khi nào bạn sanitization nó. Nói một cách đơn giản – xác thực dữ liệu của bạn(kiểm tra xem nó cần phải ra sao – và nó “hợp lệ”) ngay khi bạn nhận được dữ liệu từ người dùng. Khi bạn đến để sử dụng dữ liệu này, ví dụ như khi bạn xuất nó, bạn cần escape(hoặc sanitization) dữ liệu đó. Hình thức sanitization này xảy ra như thế nào, hoàn toàn phụ thuộc vào tình huống sử dụng của bạn.

Lời khuyên tốt nhất là thực hiện điều này ‘muộn’: escape dữ liệu của bạn ngay trước khi bạn sử dụng hoặc hiển thị nó. Bằng cách này, bạn có thể tự tin rằng dữ liệu của mình đã được sanitization đúng cách và bạn không cần phải nhớ xem liệu dữ liệu đã được kiểm tra trước đó.

Bạn có thể nghĩ “Ok, xác nhận trước khi ghi vào cơ sở dữ liệu và sanitization khi sử dụng nó. Nhưng tôi không cần đảm bảo dữ liệu an toàn để ghi vào cơ sở dữ liệu? “. Cơ bản là . Khi thêm dữ liệu vào cơ sở dữ liệu hoặc đơn giản là sử dụng dữ liệu nhập vào để tương tác với cơ sở dữ liệu, bạn sẽ cần phải escape dữ liệu trong trường hợp có chứa bất kỳ lệnh SQL nào. Nhưng điều này đưa tôi đến Quy tắc số 3, một quy tắc đối mặt với Quy tắc số 1: Tin tưởng WordPress.

Trong một bài viết trước đó, tôi đã lấy dữ liệu đầu vào của người dùng(được gửi từ một form tìm kiếm bằng AJAX) và sử dụng nó trực tiếp với get_posts() để trả về các bài đăng phù hợp với truy vấn tìm kiếm đó:

1
2
3
$posts = get_posts( array(
    's'=>$_REQUEST['term']
) );

Một độc giả quan sát nhận thấy rằng tôi đã không thực hiện bất kỳ sanitization nào – và họ đã đúng. Nhưng tôi đã không cần. Khi bạn sử dụng các hàm cấp cao như get_posts(), bạn không cần phải lo lắng về việc sanitization dữ liệu – bởi vì tất cả các truy vấn cơ sở dữ liệu đều được escape ra khỏi WordPress. Đây là một vấn đề hoàn toàn khác nếu bạn đang sử dụng truy vấn SQL trực tiếp – nhưng chúng ta sẽ xem xét vấn đề này trong phần sau. Tương tự, các hàm như the_title()the_permalink()the_content() v.v … thực hiện sanitization riêng của chúng(cho tình huống thích hợp).

Khi bạn nhận được dữ liệu do người dùng nhập vào, quan trọng là phải xác thực nó. (Các thiết lập API, đã trình bày trong loạt bài này, cho phép bạn chỉ định hàm callback để thực hiện điều này chính xác). Dữ liệu không hợp lệ được tự động sửa hoặc quá trình bị hủy bỏ và người dùng được đưa trở lại form để thử lại(hy vọng với thông báo lỗi thích hợp). Mối quan tâm ở đây không phải là an toàn mà là tính hợp lệ – nếu bạn làm đúng, WordPress sẽ xử lý việc thêm dữ liệu vào cơ sở dữ liệu một cách an toàn. “Valid”(hợp lệ) nghĩa là gì tùy thuộc vào bạn – có thể nghĩa là địa chỉ email hợp lệ, số nguyên dương, văn bản có độ dài giới hạn hoặc một trong các array có tùy chọn chỉ định. Tuy nhiên, mục đích của bạn là xác định tính hợp lệ, WordPress cung cấp rất nhiều hàm hữu ích.

Khi mong đợi dữ liệu number, có thể kiểm tra xem dữ liệu ‘là một kiểu number’, ví dụ is_int hoặc is_float. Thông thường, chỉ đơn giản là truyền dữ liệu dưới dạng số với: intval hoặc floatval.

Nếu bạn cần muốn con số được thêm vào các số 0 đứng đầu, WordPress cung cấp hàm zeroise(). Hàm này lấy các tham số sau:

  • Number – số cần được chèn
  • Threshold – số chữ số sẽ được chèn đệm vào number

Ví dụ:

1
echo zeroise(70,4); // Prints 0070

Để kiểm tra tính hợp lệ của email, WordPress có hàm is_email(). Hàm này sử dụng các phép kiểm tra đơn giản để xác nhận địa chỉ. Chẳng hạn, nó kiểm tra xem email có chứa ký hiệu ‘@’ hay không, có dài hơn 3 ký tự, tên domain chỉ chứa các chữ số và dấu gạch ngang, v.v. Rõ ràng, hàm này không kiểm tra xem địa chỉ email thực sự tồn tại. Giả sử địa chỉ e-mail đã vượt qua bài kiểm tra, nó sẽ được trả về, nếu không sẽ trả về ‘false’.

1
2
3
4
5
$email = is_email('someone@e^ample.com');
// $email is set to false.
$email = is_email('someone@example.com');
// $email is set to 'someone@example.com'.

Thường có thể bạn chỉ muốn cho phép một số tag của HTML trong dữ liệu của mình – ví dụ như trong các bình luận được đăng trên website của bạn. WordPress cung cấp một nhóm các hàm có dạng wp_kses_*(KSES Strips Evil Sc scripts). Các hàm này loại bỏ(một số tập hợp con) tag của HTML và có thể được dùng để đảm bảo rằng các liên kết trong dữ liệu là các giao thức được chỉ định. Ví dụ, hàm wp_kses() nhận ba đối số:

  • content -(string) Nội dung để lọc qua các nút
  • allowed_html – Một array với mỗi key là một phần tử HTML được phép và giá trị là một mảng các thuộc tính được phép cho phần tử đó
  • allow_protocols – không bắt buộc. Giao thức được hỗ trợ trong các liên kết(ví dụ httpmailtofeed, v.v.)

wp_kses() là một hàm rất linh hoạt, cho phép bạn xóa các tag không mong muốn hoặc chỉ các thuộc tính không mong muốn khỏi các tag. Ví dụ: chỉ cho phép các thẻ <strong> hoặc <a> (nhưng chỉ cho phép thuộc tính href):

1
2
3
4
5
6
7
8
9
$content = "<em>Click</em> <a title='click for wp.tuts+' href='http://wp.tutsplus.com'>here</a> to visit <strong> wptuts+ </strong>";
echo wp_kses( $content, array(
    'strong' => array(),
    'a' => array('href')
) );
// Prints the HTML "Click <a href='http://wp.tutsplus.com'>here</a> to visit <strong> wptuts+ </strong>":
Click <a href="http://wp.tutsplus.com">here</a> to visit <strong> wptuts+ </strong>

Tất nhiên, việc chỉ định các tag được dùng và từng attribute(thuộc tính) được dùng sẽ là một nhiệm vụ Vì vậy, WordPress cung cấp các hàm khác cho phép bạn sử dụng wp_kses với các thẻ và giao thức được phép đặt trước – cụ thể là các hàm được sử dụng để xác thực bài đăng và nhận xét:

Các hàm trên rất hữu ích trong việc đảm bảo rằng HTML từ người dùng chỉ chứa các thành phần an toàn. Khi chúng tôi thực hiện xong, chúng tôi cũng muốn đảm bảo rằng tag mở có tag đóng tương ứng. Đối với điều này, chúng ta có thể sử dụng balanceTags(). Hàm này nhận hai đối số:

  • content – Nội dung để lọc và cân bằng các tag của
  • force balance – True hay fasle, để ép việc cân bằng các tag.
1
2
3
4
5
6
// Content with missing closing </strong> tag
$content = "<em>Click</em> <a href='http://wp.tutsplus.com'>here</a> to visit <strong> wptuts+";
echo balanceTags($content,true),
// Prints the HTML "Click <a href='http://wp.tutsplus.com'>here</a> to visit <strong> wptuts+ </strong>"

Nếu bạn muốn tạo một file trong một trong các thư mục của website của mình, bạn sẽ muốn đảm bảo tên file là hợp lệ và chính thức. Bạn cũng muốn đảm bảo rằng tên file là duy nhất trong thư mục đó. Đối với điều này WordPress cung cấp:

  • sanitize_file_name($filename) – sanitize (hoặc validate) tên file bằng cách xóa các ký tự không hợp lệ trong tên file trên các hệ điều hành nhất định hoặc sẽ yêu cầu escape khỏi dòng lệnh. Thay thế khoảng trắng bằng dấu gạch ngang và dấu gạch ngang liên tiếp bằng một dấu gạch ngang và loại bỏ dấu chấm, dấu gạch ngang và dấu gạch dưới từ đầu và cuối tên file.
  • wp_unique_filename($dir, $filename) – trả về một filename duy nhất(cho thư mục $dir) và được sanitize(sử dụng sanitize_file_name).

Khi nhận dữ liệu được nhập vào text field, có thể bạn sẽ muốn loại bỏ các space, tab và line break(ngắt dòng), cũng như lược bỏ tag bất kỳ. Trường hợp này WordPress có sanitize_text_field().

WordPress cũng có sanitize_key. Đây là một hàm thông dụng(và đôi khi hữu ích). Nó chỉ đơn giản là đảm bảo biến trả về chỉ chứa các chữ số alpha, dấu gạch ngang và dấu gạch dưới.

Trong khi đó việc xác nhận có liên quan đến việc đảm bảo dữ liệu là hợp lệ – sanitization dữ liệu là về việc làm cho nó an toàn. Mặc dù một số hàm xác thực được đề cập ở trên có thể hữu ích trong việc đảm bảo dữ liệu an toàn – nói chung là không đủ. Ngay cả dữ liệu ‘hợp lệ’ cũng có thể không an toàn trong các tình huống nhất định.

Nói đơn giản bạn không thể hỏi “Làm thế nào để tôi khiến dữ liệu này an toàn?”. Thay vào đó, bạn nên hỏi, “Làm sao để tôi làm cho dữ liệu này an toàn khi sử dụng nó trong X“.

Để minh họa luận điểm này, giả sử bạn có một widget với textarea, đây là nơi bạn sẽ cho người dùng nhập vào HTML. Giả sử họ nhập:

1
<textarea name="my-textarea"></textarea> Hello World

Code này là hoàn toàn hợp lệ và an toàn, HTML – tuy nhiên khi bạn nhấp save, chúng tôi thấy rằng văn bản đã nhảy ra khỏi textarea. Code HTML không phải giá trị an toàn cho textarea.

Điều an toàn để sử dụng trong một tình huống, không hẳn sẽ an toàn trong một tình huống khác. Bất cứ khi nào bạn sử dụng hoặc hiển thị dữ liệu, bạn phải ghi nhớ những hình thức sanitization cần phải được thực hiện để làm cho việc sử dụng dữ liệu đó an toàn. Đây là lý do tại sao WordPress thường cung cấp một số hàm cho cùng nội dung, ví dụ:

  • the_title – để sử dụng title trong HTML tiêu chuẩn(ví dụ bên trong thẻ title)
  • the_title_attribution – để sử dụng title như giá trị của thuộc tính(thường là thuộc tính title <a> trong tag)
  • the_title_rss – để sử dụng title trong nguồn cấp RSS

Tất cả đều thực hiện việc sanitization cần thiết cho một tình huống cụ thể – và nếu bạn đang sử dụng chúng, bạn nên chắc chắn đã sử dụng đúng. Tuy nhiên, đôi khi, chúng tôi sẽ cần thực hiện sanitization riêng của mình – thường vì chúng tôi có dữ liệu nhập bổ sung ngoài title của post, permalink, content, v.v. WordPress xử lý cho việc đó.

Khi in các biến ra trang, chúng ta cần lưu ý về cách trình duyệt sẽ biên dịch chúng. Hãy xem xét ví dụ sau:

1
<h1> <?php echo $title; ?> </h1>

Giả sử $title = < script>alert('Injected Javascript')</script> Thay vì hiển thị các tag HTML <script> , chúng sẽ được biên dịch thành HTML, và phần javascript sẽ được chèn vào trang. HTML, chúng sẽ được hiểu là HTML và javascript kèm theo sẽ được đưa vào trang.

Hình thức injection này(cũng được trình bày trong ví dụ của form tìm kiếm) được gọi là Cross-site scripting và ví dụ đơn giản này cho thấy mức độ nghiêm trọng. Injected script về cơ bản có thể kiểm soát trình duyệt và ‘nhân danh’ người dùng hoặc đánh cắp cookie của người dùng. Điều này trở thành một vấn đề thậm chí nghiêm trọng hơn nếu người dùng có đăng nhập. Để ngăn các biến được in ra trong HTML được hiểu là HTML, WordPress cung cấp hàm esc_html nổi tiếng. Trong ví dụ này:

1
<h1> <?php echo esc_html($title); ?> </h1>

Bây giờ hãy xem xét ví dụ sau:

1
2
<?php $value = 'my-value" onfocus="alert(\"Injected javascript\")"'; ?>
<input type="text" name="myInput" value="<?php echo $value;?>"/>

Vì $value dấu ngoặc kép, không escape, nó có thể vượt khỏi phạm vi giá trị của atribute, ví dụ, bằng cách sử dụng thuộc tính onfocus. Để escape các ký tự không an toàn(như dấu ngoặc đơn và dấu ngoặc kép trong trường hợp này), WordPress cung cấp hàm esc_attr. Giống như esc_html, nó thay thế các ký tự ‘không an toàn’ bằng các thực thể tương đương. Trên thực tế, tại thời điểm bài viết, các hàm này giống hệt nhau – nhưng bạn vẫn nên sử dụng hàm phù hợp với tình huống.

Trong ví dụ này, chúng ta nên có:

1
2
<?php $value = 'my-value" onfocus="alert(\"Injected javascript\")"'; ?>
<input type="text" name="myInput" value="<?php echo esc_attr($value);?>"/>

Cả esc_html và esc_attr cũng đi kèm với các biến thể ___e và _x.

  • esc_html__('Văn bản cần dịch', 'tên miền plugin')esc_attr__– trả về văn bản dịch đã escape,
  • esc_html_e('Văn bản cần dịch', 'tên miền plugin')esc_attr_e – hiển thị văn bản dịch đã escape và cuối cùng là
  • esc_html_x('Văn bản cần dịch', $context, 'tên miền plugin') / esc_attr_x – dịch văn bản theo tình huống đã truyền vào, sau đó trả về bản dịch đã escape

Đối với tên class, WordPress cung cấp sanitize_html_group – điều này escape các biến để sử dụng trong tên class, đơn giản bằng cách giới hạn giá trị được trả về ở dạng alpha-numeric, hyphen (dấu gạch nối) và underscore (dấu gạch dưới). Lưu ý: Nó không đảm bảo tên class là hợp lệ (tham khảo: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier).

Trong CSS, identifier chỉ có thể chứa các ký tự [a-zA-Z0-9] và ISO 10646 ký tự U + 00A0 trở lên, cộng với hyphen (-) và underscore (_); chúng không thể bắt đầu bằng digit (chữ số), hai hyphens hoặc dấu gạch nối theo sau là digit (chữ số). Identifier có thể chứa các ký tự escape và bất kỳ ký tự ISO 10646 nào dưới dạng numeric code.

Bây giờ chúng ta hãy xem xét một thực hành phổ biến khác, in các biến thành thuộc tính href:

1
<a href="<?php echo $url;?>" title="Link Title"> Link Text </a>

Rõ ràng nó dễ bị tấn công bằng hình thức tấn công đã minh họa trong việc escape HTML và các thuộc tính. Nhưng điều gì sẽ xảy ra nếu $url được thiết lập như sau:

1
$url = 'javascript:alert(\'Injected javascript\')'

Khi nhấp vào liên kết, hàm alert sẽ bị loại bỏ. Hàm này không chứa HTML hoặc bất kỳ trích dẫn nào cho phép nó vượt ra khỏi thuộc tính href – vì vậy ở đây esc_attr là không đủ. Đây là lý do tại sao tình huống trở nên quan trọng: esc_attr($url) sẽ an toàn với thuộc tính title, nhưng không phải cho thuộc tính href – và việc này là do giao thức javascript – trong khi hoàn toàn hợp lệ – không được coi là an toàn trong tình huống này. Thay vào đó bạn nên sử dụng:

  • esc_url – để escape các URL sẽ được in ra trang.
  • esc_url_raw – để escape URL để lưu vào cơ sở dữ liệu hoặc sử dụng trong việc chuyển hướng URL.

esc_url loại bỏ các ký tự vi phạm khác nhau, và thay thế dấu ngoặc kép và ký hiệu bằng các thực thể tương đương. Sau đó, nó kiểm tra xem giao thức đang được sử dụng có được hợp lệ hay không (mặc định không phải javascript).

Những gì esc_url_raw thực hiện gần giống với esc_url, nhưng nó không thay các thế ký hiệu và dấu ngoặc đơn (mà bạn không muốn, khi sử dụng URL thành URL, thay vì hiển thị URL).

Trong ví dụ này, chúng tôi đang hiển thị URL, vì vậy chúng tôi sử dụng esc_url:

1
<a href="<?php echo esc_url($url);?>" title="Link Title"> Link Text </a>

Mặc dù đa số các trường hợp là không cần thiết trong, nhưng cả hai hàm đều nhận một array tùy chọn để chỉ định giao thức nào (như httphttpsftpftpsmailto, v.v.) mà bạn cho phép.

Đôi khi, bạn sẽ muốn in các biến javascript lên một trang (thường ở head):

1
2
3
<script>
var myVar = '<?php echo $variable; ?>';
</script>

Trong thực tế, nếu bạn đang làm điều này, gần như chắc chắn bạn sẽ sử dụng wp_localize_script() – hàm xử lý sanitization cho bạn. (Nếu bất cứ ai có thể nghĩ ra một lý do tại sao bạn có thể cần phải sử dụng phương pháp trên thay vào đó, tôi muốn nghe nó).

Tuy nhiên, để làm cho ví dụ trên an toàn, bạn có thể sử dụng hàm esc_js:

1
2
3
<script>
var myVar = '<?php echo esc_js($variable); ?>';
</script>

Khi hiển thị nội dung trong textarea, esc_html là không đủ vì nó không nhân đôi thực thể encode. Ví dụ:

1
2
<?php $var = '<strong>text</strong> &lt;b&gt;bold&lt;/b&gt;' ?>
<textarea><?php echo esc_html($var); ?> </textarea>

$var được in ra trong textarea sẽ xuất hiện dưới dạng:

1
<strong>text</strong> <b>bold</b>

Thay vì cũng encode & thành &amp; trong thẻ <b>.

Đối với điều này, WordPress cung cấp esc_textarea, gần giống với esc_html, nhưng thực hiện encode 2 lần. Về cơ bản, nó ít hơn wrapper cho htmlspecialchars. Trong ví dụ này:

1
2
<?php $var = '<strong>text</strong> &lt;b&gt;bold&lt;/b&gt;' ?>
<textarea><?php echo esc_textarea($var); ?> </textarea>

Hiển thị địa chỉ e-mail trên website của bạn khiến các email này dễ bị lấy đi. Một phương pháp đơn giản là ngụy trang địa chỉ email. WordPress cung cấp antispambot, encode ngẫu nhiên các thành phần của địa chỉ email thành các thực thể HTML của chúng (và tương đương thập lục phân nếu $mailto = 1). Mỗi khi trang được tải, encode phải khác biệt và trong khi địa chỉ được trả về hiển thị chính xác trong trình duyệt, nó sẽ xuất hiện dưới dạng gobbledygook đến spambots. Hàm nhận hai đối số:

  • e-mail – địa chỉ để xáo trộn
  • mailto – 1 hoặc 0 (1 nếu sử dụng giao thức mailto trong thẻ liên kết)
1
2
3
$email = "joebloggs@example.com";
$email = sanitize_email($email);
echo '<a href="mailto:'.antispambot($email,1).'" title="Click to e-mail me" >'.antispambot($email).' </a>';

Nếu bạn muốn thêm (hoặc xóa) các biến khỏi string truy vấn (điều này rất hữu ích nếu bạn muốn cho phép người dùng chọn thứ tự cho các bài đăng của mình), cách an toàn và dễ nhất là sử dụng add_query_arg và remove_query_arg. Các hàm này xử lý tất cả các escape cần thiết cho các đối số và giá trị của chúng để sử dụng trong URL.

add_query_arg nhận hai đối số:

  • tham số truy vấn – một array kết hợp của tham số -> giá trị
  • url – URL để thêm các tham số và giá trị của chúng vào. Nếu bị bỏ qua, URL của trang hiện tại được sử dụng

remove_query_arg cũng nhận hai đối số, đầu tiên là array chứa các tham số cần loại bỏ, đối số thứ hai như trên.

1
2
3
4
5
6
// If we are at www.example.com/wp-admin/edit.php?post_type=book
$query_params = array ('page' => 'my-bage');
$url = add_query_arg( $query_params );
// Would set $url to be:
// www.example.com/wp-admin/edit.php?post_type=book&page=my-page

Như đã đề cập trước đây, việc sanitize không có ý nghĩa gì nếu không có tình huống cụ thể – vì vậy việc sanitization dữ liệu khi ghi vào cơ sở dữ liệu là vô nghĩa. Thông thường, dù sao bạn cũng cần lưu trữ dữ liệu ở định dạng thô và trong tất cả trường hợp – Quy tắc số 1 chỉ ra chúng ta phải luôn sanitization dữ liệu xuất ra.

Việc xác thực dữ liệu, mặt khác, nên được thực hiện ngay khi nhận được và trước khi được ghi vào cơ sở dữ liệu. Ý tưởng là dữ liệu ‘không hợp lệ’ nên được tự động sửa hoặc được gắn cờ với dữ liệu và chỉ nên cung cấp dữ liệu hợp lệ cho cơ sở dữ liệu.

Có nghĩa là – bạn cũng có thể muốn thực hiện xác nhận khi dữ liệu cũng được hiển thị. Đôi khi trên thực tế, ‘validation’ cũng sẽ đảm bảo dữ liệu an toàn. Nhưng ưu tiên ở đây là sự an toàn và bạn nên tránh việc xác thực quá mức cho mỗi lần tải trang (ví dụ, các hàm wp_kses_* thực hiện rất tốn kém).

Khi sử dụng các hàm như get_posts hoặc các class như WP_Query và WP_User_Query, WordPress sẽ đảm nhiệm việc sanitization cần thiết khi truy vấn cơ sở dữ liệu. Tuy nhiên, khi lấy dữ liệu từ một table tùy chỉnh hoặc thực hiện truy vấn SQL trực tiếp trên cơ sở dữ liệu – việc sanitization đúng cách phụ thuộc vào bạn. Tuy nhiên, WordPress cung cấp một class hữu ích, class $wpdb, giúp escape các truy vấn SQL.

Chúng ta hãy xem xét lệnh ‘SELECT‘ cơ bản này, trong đó $age và $firstname là các biến lưu trữ age và name mà chúng ta đang truy vấn:

1
SELECT * WHERE age='$age' AND firstname = '$firstname'

Chúng tôi đã không escape khỏi các biến này, vì vậy các lệnh có tiềm năng hơn có thể được chèn vào. Mượn ví dụ của xkcd ở bên trên:

1
2
3
4
$age = 14;
$firstname = "Robert'; DROP TABLE Students;";
$sql = "SELECT * WHERE age='$age' AND firstname = '$firstname';";
$results = $wpdb->query

Sẽ chạy như các lệnh:

1
SELECT * WHERE age='14' AND firstname = 'Robert'; DROP TABLE Students;';

Và xóa toàn bộ bảng Students của chúng tôi.

Để ngăn điều này, chúng ta có thể sử dụng phương thức $wpdb->prepare. Phương thức này nhận hai tham số:

  • Lệnh SQL dưới dạng một string, trong đó các biến string được thay thế bằng placeholder %s và các số thập phân được thay thế bằng place-holder %d và float được thay bằng %f.
  • Một array các giá trị cho các placeholder ở trên, theo thứ tự chúng xuất hiện trong truy vấn

Trong ví dụ này:

1
2
3
4
$age = 14;
$firstname = "Robert'; DROP TABLE Students;";
$sql = $wpdb->prepare('SELECT * WHERE age=%d AND firstname = %s;',array($age,$firstname));
$results = $wpdb->get_results($sql);

Truy vấn SQL đã escape ($sql trong ví dụ này) sau đó có thể được sử dụng với một trong các phương thức:

  • $wpdb-> get_row($sql)
  • $wpdb-> get_var($sql)
  • $wpdb-> get_results($sql)
  • $wpdb-> get_col($sql)
  • $wpdb-> truy vấn($sql)

Để thêm mới hoặc cập nhật dữ liệu, WordPress giúp mọi việc dễ dàng hơn bằng cách cung cấp các phương thức $wpdb-> insert() và $wpdb-> update().

Phương thức $wpdb->insert() nhận ba đối số:

  • Table name – tên của bảng
  • Data – mảng dữ liệu để chèn dưới dạng cặp cột>> giá trị
  • Formats – mảng định dạng cho các giá trị tương ứng (‘%s‘, ‘%d‘ hoặc ‘%f‘)
1
2
3
4
5
6
7
$age = 14;
$firstname = "Robert'; DROP TABLE Students;";
$wpdb->insert(
    'Students',
    array( 'firstname' => $firstname, 'age' => $age ),
    array( '%s', '%d' )
);

Phương thức $wpdb->update() nhận năm đối số:

  • Table name – tên của bảng
  • Data – mảng dữ liệu cần cập nhật dưới dạng cặp column->value
  • Where – mảng dữ liệu khớp với các cặp column->value
  • Data Format – mảng định dạng cho các giá trị dữ liệu tương ứng
  • Where Format – array của các định dạng cho các giá trị ‘where’ tương ứng
01
02
03
04
05
06
07
08
09
10
11
// Update Robert'; DROP TABLE Students; to Bobby
$oldname = "Robert'; DROP TABLE Students;";
$newname = "Bobby";
$wpdb->update(
    'Students',
    array( 'firstname' => $newname ),
    array( 'firstname' => $oldname ),
    array( '%s' ),
    array( '%s' )
);

Cả hai phương thức $wpdb-> insert() và $wpdb->update() đều thực hiện tất cả các sanitization cần thiết cho tác vụ ghi vào cơ sở dữ liệu.

Vì phương thức $wpdb->prepare sử dụng % để phân biệt place-holder, nên cần thận trọng khi sử dụng ký tự % ký tự đại diện trong các câu lệnh LIKE của SQL. Codex đề xuất escape bằng một % thứ hai. Ngoài ra, bạn có thể escape cụm từ được tìm kiếm bằng like_escape và sau đó thêm ký tự % khi thích hợp, trước khi đưa cụm từ này vào truy vấn bằng phương thức prepare. Ví dụ:

1
2
3
$age=14;
$firstname = "Robert'; DROP TABLE Students;";
SELECT * WHERE age=$age (firstname LIKE '%$firstname%');

Sẽ thực hiện an toàn với:

1
2
3
4
$age=14;
$firstname = "Robert'; DROP TABLE Students;";
SELECT * WHERE age=$age AND (firstname LIKE '%$firstname%');
$query = $wpdb->prepare('SELECT * WHERE age=%d AND (firstname LIKE %s);', array($age, '%'.like_escape($firstname).'%') );

Đây không phải danh sách đầy đủ các hàm có sẵn để validate và sanitize, nhưng nó sẽ bao gồm phần lớn các trường hợp sử dụng. Rất nhiều hàm(và các hàm khác) này có thể được tìm thấy trong /wp-includes/formatted.php và tôi thực sự khuyên bạn nên đào sâu vào code và xem xét cách WordPress thực hiện validate và sanitize dữ liệu.

Bạn thấy bài viết này hữu ích không? Bạn có thêm đề xuất nào về các thực tiễn tốt nhất để validate và sanitizie dữ liệu trong WordPress không? Hãy cho chúng tôi biết trong các bình luận dưới đây.

You May Also Like

About the Author: admin

Leave a Reply

Your email address will not be published. Required fields are marked *