{"id":1854,"date":"2020-08-14T17:47:59","date_gmt":"2020-08-14T10:47:59","guid":{"rendered":"https:\/\/wptips.dev\/?p=1854"},"modified":"2020-08-14T17:50:14","modified_gmt":"2020-08-14T10:50:14","slug":"what-is-wordpress-nonce-preventing-csrf-attack","status":"publish","type":"post","link":"https:\/\/pixelstudio.id\/blog\/what-is-wordpress-nonce-preventing-csrf-attack\/","title":{"rendered":"What is WordPress Nonce? (Preventing CSRF Attack)"},"content":{"rendered":"\n<p>Let&#8217;s say you installed a <strong>Forum plugin<\/strong> that can create a new thread, manage your profile, change password, etc.<\/p>\n\n\n\n<p>Then someone malicious came in and post a link that will trigger password change to &#8220;123456&#8221;. The link might say &#8220;Won $10.000&#8221; or something attractive so more people got tricked by it.<\/p>\n\n\n\n<p>Now that person have access to the victim&#8217;s account.<\/p>\n\n\n\n<p>This kind of attack is called <strong>CSRF<\/strong> (Cross Site Request Forgery) where a 3rd party sends a fake request. The damage can be devastating.<\/p>\n\n\n\n<p>Is the above scenario possible? Yes, unless the plugin author added a prevention measure using <strong>Nonce<\/strong>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What is Nonce?<\/h2>\n\n\n\n<p>Nonce is a <strong>randomly-generated string<\/strong> attached to a URL or Form to verify that an action is done by the user him\/herself.<\/p>\n\n\n\n<p>The string is one-time use and different for each user. That means it&#8217;s impossible to fake. If the nonce is not valid, we can reject the request.<\/p>\n\n\n\n<p>Here&#8217;s a diagram showing 2 requests, 1 from the user, and 1 from a hacker that got rejected:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1089\" height=\"521\" src=\"https:\/\/pixelstudio.id\/blog\/wp-content\/uploads\/2020\/08\/nonce-diagram-works.jpg\" alt=\"\" class=\"wp-image-1858\" srcset=\"https:\/\/pixelstudio.id\/blog\/wp-content\/uploads\/2020\/08\/nonce-diagram-works.jpg 1089w, https:\/\/pixelstudio.id\/blog\/wp-content\/uploads\/2020\/08\/nonce-diagram-works-480x230.jpg 480w\" sizes=\"auto, (max-width: 1089px) 100vw, 1089px\" \/><figcaption>Diagram showing how nonce works.<br>Hacker that posts fake data will be rejected because nonce is empty or not valid.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Is My Website Vulnerable to CSRF?<\/h2>\n\n\n\n<p>First, identify which of your link or form <strong>could cause negative effect<\/strong> on your site. <\/p>\n\n\n\n<p>Something public like Contact Form is fine without nonce. What&#8217;s the worst thing that could happen anyway? Get spammed? Nonce won&#8217;t solve that.<\/p>\n\n\n\n<p><strong>Found Potentially harmful Form?<\/strong><\/p>\n\n\n\n<p>For example, we have the Password Change form in WooCommerce account page.<\/p>\n\n\n\n<p>Open Web Inspector (F12) and check whether the form has a hidden field containing the nonce or not.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"192\" src=\"https:\/\/pixelstudio.id\/blog\/wp-content\/uploads\/2020\/08\/nonce-check-if-exists.jpg\" alt=\"\" class=\"wp-image-1859\" srcset=\"https:\/\/pixelstudio.id\/blog\/wp-content\/uploads\/2020\/08\/nonce-check-if-exists.jpg 750w, https:\/\/pixelstudio.id\/blog\/wp-content\/uploads\/2020\/08\/nonce-check-if-exists-480x123.jpg 480w\" sizes=\"auto, (max-width: 750px) 100vw, 750px\" \/><figcaption>WooCommerce&#8217;s password change form has nonce field<\/figcaption><\/figure>\n\n\n\n<p>Yes, it has a nonce field. But to be sure, try removing that nonce field and submit the form.<\/p>\n\n\n\n<p>Does it still change the password? In the case of Woocommerce, it fails (which is the correct behavior).<\/p>\n\n\n\n<p><strong> Found Potentially harmful Link?<\/strong><\/p>\n\n\n\n<p>For example, we have WooCommerce Marketplace plugin. Users can post and delete their own products.<\/p>\n\n\n\n<p>That delete button seems dangerous right?<\/p>\n\n\n\n<p>Open web inspector and check out the link. If it has a nonce then it&#8217;s safe:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">https:\/\/myshop.com\/delete-product\/1042?_wpnonce=75ad822113<\/code><\/pre>\n\n\n\n<p>But just to be sure, copy the link, and remove the nonce. So you have:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">https:\/\/myshop.com\/delete-product\/1042<\/code><\/pre>\n\n\n\n<p>Then paste it in a new tab. See if your product got deleted. If it&#8217;s deleted, your site is vulnerable to CSRF.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How to Implement Nonce?<\/h2>\n\n\n\n<p>This is useful if you want to create your own form or plugin.<\/p>\n\n\n\n<p><strong>GENERATE NONCE<\/strong><\/p>\n\n\n\n<p>There are 3 ways to generate a nonce:<\/p>\n\n\n\n<ul><li><a rel=\"noreferrer noopener\" href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_create_nonce\/\" target=\"_blank\">wp_create_nonce()<\/a>&nbsp;\u2013 Create a plain nonce, use it anyway you like.<\/li><li><a rel=\"noreferrer noopener\" href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_nonce_url\/\" target=\"_blank\">wp_nonce_url()<\/a>&nbsp;\u2013 Appending a <code>_wpnonce<\/code> parameter to a URL.<\/li><li><a rel=\"noreferrer noopener\" href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_nonce_field\/\" target=\"_blank\">wp_nonce_field()<\/a>&nbsp;\u2013 Echoing a hidden field containing nonce.<\/li><\/ul>\n\n\n\n<p>Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"php\" class=\"language-php\">$nonce = wp_create_nonce( 'add_product' );\n\/\/ zxcvbn678\n\n$url = 'https:\/\/myshop.com\/';\n$nonce_url = wp_nonce_url( $url, 'delete_product' );\n\/\/ https:\/\/myshop.com\/_wpnonce=abcdef123\n\nwp_nonce_field( 'change_password' );\n\/\/ &lt;input type=\"hidden\" id=\"_wpnonce\" name=\"_wpnonce\" value=\"qwerty123\" \/><\/code><\/pre>\n\n\n\n<p><strong>VERIFY NONCE<\/strong><\/p>\n\n\n\n<p>Use <a rel=\"noreferrer noopener\" href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_verify_nonce\/\" target=\"_blank\">wp_verify_nonce()<\/a> by passing in the nonce and its name.<\/p>\n\n\n\n<p>For example, the code below handles form submission:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"php\" class=\"language-php\">$nonce = $_POST['_wpnonce'];\n\nif( wp_verify_nonce( $nonce, 'change_password' ) ) {\n  \/\/ success!, process the password change\n  \/\/ ...\n} else {\n  return false; \/\/ abort it\n}<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator is-style-dots\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>CSRF is the <strong>most common vulnerabilities<\/strong> found in WordPress plugins.<\/p>\n\n\n\n<p>It is important to be cautious when choosing a plugin, especially when it has low popularity. A small amount of users means it takes longer for someone to found the loophole.<\/p>\n\n\n\n<p>Having said that, popular plugins are not always 100% safe. But when a potential threat is found, usually it is quickly patched. So it&#8217;s important to always <strong>keep your plugins up-to-date<\/strong>.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>That&#8217;s all, I hope you found this article useful. If you have any question, please post it in the comment below \ud83d\ude42<\/p><\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>CSRF is the most common vulnerabilities found in WordPress plugins. And Nonce (number used once) can fix that. Let&#8217;s learn how!<\/p>\n","protected":false},"author":1,"featured_media":1863,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[31,48],"class_list":["post-1854","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-general","tag-php","tag-security"],"blocksy_meta":"","_links":{"self":[{"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/posts\/1854","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/comments?post=1854"}],"version-history":[{"count":9,"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/posts\/1854\/revisions"}],"predecessor-version":[{"id":1867,"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/posts\/1854\/revisions\/1867"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/media\/1863"}],"wp:attachment":[{"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/media?parent=1854"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/categories?post=1854"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/tags?post=1854"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}