Reputation: 192497
Smart Wordpress people say that plugin developers should employ a nonce in each AJAX request that is sent from a page back to the wordpress blog (admin-ajax.php).
This is done by (1) generating a nonce on the server side, via
$nonce = wp_create_nonce ('my-nonce');
...(2) making that nonce available to Javascript code that sends AJAX requests. For example you could do it like this:
function myplg_emit_scriptblock() {
$nonce = wp_create_nonce('myplg-nonce');
echo "<script type='text/javascript'>\n" .
" var WpPlgSettings = {\n" .
" ajaxurl : '" . admin_url( 'admin-ajax.php' ) . "',\n" .
" nonce : '" . $nonce . "'\n" .
" };\n" .
"</script>\n";
}
add_action('wp_print_scripts','myplg_emit_scriptblock');
...and then (3) the javascript ajax logic references that global variable.
var url = WpPlgSettings.ajaxurl +
"?action=my-wp-plg-action&" +
"nonce=" + WpPlgSettings .nonce +
"docid=" + id;
$.ajax({type: "GET",
url: url,
headers : { "Accept" : 'application/json' },
dataType: "json",
cache: false,
error: function (xhr, textStatus, errorThrown) {
...
},
success: function (data, textStatus, xhr) {
...
}
});
...and finally (4) checking the received nonce in the server-side logic.
add_action( 'wp_ajax_nopriv_skydrv-hotlink', 'myplg_handle_ajax_request' );
add_action( 'wp_ajax_skydrv-hotlink', 'myplg_handle_ajax_request' );
function myplg_handle_ajax_request() {
check_ajax_referer( 'myplg-nonce', 'nonce' ); // <<=-----
if (isset($_GET['docid'])) {
$docid = $_GET['docid'];
$response = myplg_generate_the_response($docid);
header( "Content-Type: application/json" );
echo json_encode( $response ) ;
}
else {
$response = array("error" => "you must specify a docid parameter.");
echo json_encode( $response ) ;
}
exit;
}
But how does the check really work?
Upvotes: 5
Views: 10734
Reputation: 26065
Revising some AJAX procedures, I came to the same question. And it's a simple matter of checking the function code:
function check_ajax_referer( $action = -1, $query_arg = false, $die = true ) {
if ( $query_arg )
$nonce = $_REQUEST[$query_arg];
else
$nonce = isset($_REQUEST['_ajax_nonce']) ? $_REQUEST['_ajax_nonce'] : $_REQUEST['_wpnonce'];
$result = wp_verify_nonce( $nonce, $action );
if ( $die && false == $result ) {
if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
wp_die( -1 );
else
die( '-1' );
}
do_action('check_ajax_referer', $action, $result);
return $result;
}
If wp_verify_nonce
is false
and you haven't sent false
in the $die
parameter, then it will execute wp_die( -1 );
.
In your sample code, check_ajax_referer()
will break the execution and return -1
to the AJAX call. If you want to handle the error yourself, add the parameter $die
and do your stuff with $do_check
:
$do_check = check_ajax_referer( 'myplg-nonce', 'nonce', false );
Note that the proper way to handle AJAX in WordPress is: register, enqueue and localize the JavaScript files using wp_enqueue_scripts
instead of wp_print_scripts
.
See Use wp_enqueue_scripts() not wp_print_styles().
Check this update in December 2020 from a core contributor h/t: Rafael Atías:
Upvotes: 18
Reputation: 349
It is just a test that the "nonce" code matches what was given, so a hacker can't cut in and get a shortcut to your database. If the security code doesn't match, the php will die and the page will halt.
"If you code is correctly verified it will continue past, if not it will trigger die('-1'); stopping your code dead."
Upvotes: 0