{"id":1799,"date":"2025-05-11T06:36:30","date_gmt":"2025-05-11T06:36:30","guid":{"rendered":"https:\/\/shreyapohekar.com\/blogs\/?p=1799"},"modified":"2025-05-12T05:51:23","modified_gmt":"2025-05-12T05:51:23","slug":"csrf-why-put-requests-are-safer-and-how-modern-browsers-prevent-csrf-attacks","status":"publish","type":"post","link":"https:\/\/shreyapohekar.com\/blogs\/csrf-why-put-requests-are-safer-and-how-modern-browsers-prevent-csrf-attacks\/","title":{"rendered":"CSRF &#8211; Why PUT Requests Are Safer and How Modern Browsers Prevent CSRF Attacks"},"content":{"rendered":"\n<p>Hi everyone, I\u2019m Shreya, and today I want to shed light on some lesser-discussed aspects of Cross-Site Request Forgery (CSRF). While identifying CSRF vulnerabilities during security assessments or bug bounties can often be straightforward, effectively mitigating them requires a deeper understanding of browser behavior, HTTP methods, and secure token handling. In this blog, I\u2019ll share my learnings on how CSRF attacks actually work, why some requests are more vulnerable than others, and the modern strategies you can adopt\u2014both on the client and server side\u2014to strengthen your web application&#8217;s defense against CSRF.<\/p>\n\n\n\n<p>Let&#8217;s get started from the basics.<\/p>\n\n\n\n<p>Cross-Site Request Forgery (CSRF) is a critical web security vulnerability that exploits the trust a website has in a user&#8217;s browser. Often overlooked by developers, CSRF attacks can allow malicious websites to perform unauthorized actions on behalf of authenticated users\u2014without their consent or awareness. This blog post dives deep into what CSRF is, how it works under the hood, and why it primarily affects GET and POST requests. We\u2019ll also explore why HTTP methods like PUT are generally considered immune to CSRF and how modern browsers have evolved to defend against these attacks using secure cookie policies and built-in protections.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What is CSRF?<\/h3>\n\n\n\n<p>Imagine this: You&#8217;re logged into your bank account in one browser tab. In another tab, you visit a malicious website. That malicious site can silently submit a request \u2014 like transferring money \u2014 on your behalf to your bank, and your browser will attach your bank session cookie because it&#8217;s still valid. The bank thinks the request came from you.<\/p>\n\n\n\n<p>Here\u2019s how a CSRF attack typically works:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>User logs into a trusted site (e.g., <code>example.com<\/code>)<\/strong> and obtains an active session via cookies.<\/li>\n\n\n\n<li><strong>Attacker lures the user to a malicious site (e.g., <code>attacker.com<\/code>)<\/strong>. This could happen through phishing emails, social media, or even ads.<\/li>\n\n\n\n<li><strong>The malicious site silently submits a request<\/strong> (e.g., <code>GET<\/code> or <code>POST<\/code>) to <code>example.com<\/code>.<\/li>\n\n\n\n<li><strong>Browser automatically includes the session cookie<\/strong>, and the request appears valid to the server.<\/li>\n\n\n\n<li><strong>The server executes the action<\/strong>, thinking it was initiated by the legitimate user.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Why CSRF Works with GET\/POST But Not with PUT<\/h3>\n\n\n\n<p>A common question is: <em>Why are GET and POST requests vulnerable to CSRF, while PUT and DELETE are not (or less so)?<\/em><\/p>\n\n\n\n<p>The reason lies in how browsers behave by default, particularly in how they send requests and handle <strong>CORS (Cross-Origin Resource Sharing)<\/strong> and <strong>content types<\/strong>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">GET\/POST: Vulnerable by Design<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>GET<\/strong> requests can be triggered just by loading an image, iframe, or script.<\/li>\n\n\n\n<li><strong>POST<\/strong> requests can be automatically submitted through hidden HTML forms using JavaScript or auto-submit mechanisms.<\/li>\n\n\n\n<li>Both allow browser cookies to be sent automatically without user interaction.<\/li>\n\n\n\n<li>These methods <strong>do not require preflight checks<\/strong> or any additional permissions, making them easy to exploit.<\/li>\n<\/ul>\n\n\n\n<p>Example CSRF payload using a POST form:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;form action=\"https:\/\/example.com\/delete-account\" method=\"POST\"&gt;\n  &lt;input type=\"hidden\" name=\"confirm\" value=\"yes\"&gt;\n  &lt;input type=\"submit\" value=\"Submit\"&gt;\n&lt;\/form&gt;\n&lt;script&gt;document.forms&#91;0].submit();&lt;\/script&gt;\n<\/code><\/pre>\n\n\n\n<p>This will silently send the form data to <code>example.com<\/code> if the user is logged in.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">Why PUT, DELETE, PATCH  Requests Are Safer<\/h4>\n\n\n\n<h5 class=\"wp-block-heading\">1. <strong>CORS Preflight Requirement<\/strong><\/h5>\n\n\n\n<p>When a browser sends a request with an &#8220;unsafe&#8221; HTTP method (e.g., <code>PUT<\/code>, <code>DELETE<\/code>), it <strong>first sends a preflight <code>OPTIONS<\/code> request<\/strong> to the server to check permissions. If the server does not explicitly allow the origin, the actual request is blocked.<\/p>\n\n\n\n<p>Example preflight behavior:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>OPTIONS \/update-profile HTTP\/1.1\nOrigin: https:\/\/attacker.com\nAccess-Control-Request-Method: PUT\n<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">2. <strong>Content-Type Limitations<\/strong><\/h5>\n\n\n\n<p>HTML forms can only submit a limited set of content types:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>application\/x-www-form-urlencoded<\/code><\/li>\n\n\n\n<li><code>multipart\/form-data<\/code><\/li>\n\n\n\n<li><code>text\/plain<\/code><\/li>\n<\/ul>\n\n\n\n<p>However, many modern APIs require <code>application\/json<\/code>, which <strong>cannot be submitted via HTML forms without JavaScript<\/strong> \u2014 and cross-origin JavaScript is restricted by CORS.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">3. <strong>No HTML Form Support for PUT<\/strong><\/h5>\n\n\n\n<p>HTML forms do not support methods like <code>PUT<\/code> or <code>DELETE<\/code>. They only allow <code>GET<\/code> and <code>POST<\/code>, so a CSRF payload can&#8217;t trigger them easily without special scripts.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">4. <strong>Same-Origin Policy Reinforcement<\/strong><\/h5>\n\n\n\n<p>Even if the attacker tries to send a <code>PUT<\/code> request via JavaScript, the browser\u2019s <strong>same-origin policy<\/strong> prevents it from reading or interacting with responses unless the server explicitly permits it via CORS headers.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">How Modern Browsers Help Prevent CSRF<\/h3>\n\n\n\n<p>To reduce the risk of CSRF, modern browsers now implement several built-in mechanisms that strengthen cookie behavior and reduce the chances of unauthorized cross-site interactions.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">1. <strong>SameSite Cookie Attribute<\/strong><\/h4>\n\n\n\n<p>Cookies can now include the <code>SameSite<\/code> attribute, which restricts when cookies are sent in cross-site requests.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>SameSite=Strict<\/code>: Cookies are sent only for same-site requests.<\/li>\n\n\n\n<li><code>SameSite=Lax<\/code>: Cookies are sent for top-level navigations (e.g., clicking a link).<\/li>\n\n\n\n<li><code>SameSite=None; Secure<\/code>: Cookies are sent cross-site, but only over HTTPS.<\/li>\n<\/ul>\n\n\n\n<p><strong>Example:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Set-Cookie: sessionid=xyz123; SameSite=Lax; Secure; HttpOnly\n<\/code><\/pre>\n\n\n\n<p>This helps prevent CSRF by ensuring cookies are not included in background requests from third-party sites.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">2. <strong>Default to Lax<\/strong><\/h4>\n\n\n\n<p>If no <code>SameSite<\/code> is specified, modern browsers <strong>default to <code>Lax<\/code><\/strong>, offering protection by default against most background CSRF attempts, especially via images or silent requests.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">3. <strong>Content Security Policy (CSP)<\/strong><\/h4>\n\n\n\n<p>CSP allows you to define what content can be loaded on your site. With <code>frame-ancestors<\/code>, you can prevent your site from being embedded in iframes \u2014 reducing clickjacking and CSRF via malicious UI embedding.<\/p>\n\n\n\n<p><strong>Example CSP:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Content-Security-Policy: frame-ancestors 'none';\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">4. <strong>Cross-Origin Resource Sharing (CORS)<\/strong><\/h4>\n\n\n\n<p>Properly configured CORS headers let you define <strong>which external origins<\/strong> can access your resources. If a malicious site tries to make a cross-origin request, the browser blocks it unless it&#8217;s allowed.<\/p>\n\n\n\n<p><strong>Example:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Access-Control-Allow-Origin: https:\/\/yourdomain.com\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">5. <strong>Referrer Policy<\/strong><\/h4>\n\n\n\n<p>A restrictive referrer policy minimizes the leakage of session or origin data when navigating across domains.<\/p>\n\n\n\n<p><strong>Recommended setting:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Referrer-Policy: strict-origin-when-cross-origin\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">6. <strong>Permissions Policy<\/strong><\/h4>\n\n\n\n<p>Use the <code>Permissions-Policy<\/code> (formerly <code>Feature-Policy<\/code>) to disable unnecessary APIs like geolocation, camera, or microphone for embedded or framed content.<\/p>\n\n\n\n<p><strong>Example:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Permissions-Policy: geolocation=(), camera=(), microphone=()\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Best Practices Summary<\/h3>\n\n\n\n<p>To secure your application against CSRF:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Set cookies with <code>SameSite<\/code><\/strong>, <code>Secure<\/code>, and <code>HttpOnly<\/code>.<\/li>\n\n\n\n<li><strong>Use CSRF tokens<\/strong> on all sensitive forms and API requests.<\/li>\n\n\n\n<li><strong>Limit third-party embedding<\/strong> with <code>CSP<\/code> and <code>frame-ancestors<\/code>.<\/li>\n\n\n\n<li><strong>Restrict cross-origin requests<\/strong> with <code>CORS<\/code>.<\/li>\n\n\n\n<li><strong>Minimize information leakage<\/strong> with a strong <code>Referrer-Policy<\/code>.<\/li>\n\n\n\n<li><strong>Disable unused browser features<\/strong> via <code>Permissions-Policy<\/code>.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>Thats all for this post.Tune in to <a href=\"https:\/\/shreyapohekar.com\/blogs\/understanding-csrf-tokens-server-side-handling-and-prevention-best-practices\/\" title=\"\">part 2<\/a> for more around CSRFs and how servers handles its generation, storage and validation.<br>Until then, Happy defending!<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hi everyone, I\u2019m Shreya, and today I want to shed light on some lesser-discussed aspects of Cross-Site Request Forgery (CSRF). While identifying CSRF vulnerabilities during security assessments or bug bounties can often be straightforward, effectively mitigating them requires a deeper understanding of browser behavior, HTTP methods, and secure token handling. In this blog, I\u2019ll share [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1810,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ocean_post_layout":"","ocean_both_sidebars_style":"","ocean_both_sidebars_content_width":0,"ocean_both_sidebars_sidebars_width":0,"ocean_sidebar":"","ocean_second_sidebar":"","ocean_disable_margins":"enable","ocean_add_body_class":"","ocean_shortcode_before_top_bar":"","ocean_shortcode_after_top_bar":"","ocean_shortcode_before_header":"","ocean_shortcode_after_header":"","ocean_has_shortcode":"","ocean_shortcode_after_title":"","ocean_shortcode_before_footer_widgets":"","ocean_shortcode_after_footer_widgets":"","ocean_shortcode_before_footer_bottom":"","ocean_shortcode_after_footer_bottom":"","ocean_display_top_bar":"default","ocean_display_header":"default","ocean_header_style":"","ocean_center_header_left_menu":"","ocean_custom_header_template":"","ocean_custom_logo":0,"ocean_custom_retina_logo":0,"ocean_custom_logo_max_width":0,"ocean_custom_logo_tablet_max_width":0,"ocean_custom_logo_mobile_max_width":0,"ocean_custom_logo_max_height":0,"ocean_custom_logo_tablet_max_height":0,"ocean_custom_logo_mobile_max_height":0,"ocean_header_custom_menu":"","ocean_menu_typo_font_family":"","ocean_menu_typo_font_subset":"","ocean_menu_typo_font_size":0,"ocean_menu_typo_font_size_tablet":0,"ocean_menu_typo_font_size_mobile":0,"ocean_menu_typo_font_size_unit":"px","ocean_menu_typo_font_weight":"","ocean_menu_typo_font_weight_tablet":"","ocean_menu_typo_font_weight_mobile":"","ocean_menu_typo_transform":"","ocean_menu_typo_transform_tablet":"","ocean_menu_typo_transform_mobile":"","ocean_menu_typo_line_height":0,"ocean_menu_typo_line_height_tablet":0,"ocean_menu_typo_line_height_mobile":0,"ocean_menu_typo_line_height_unit":"","ocean_menu_typo_spacing":0,"ocean_menu_typo_spacing_tablet":0,"ocean_menu_typo_spacing_mobile":0,"ocean_menu_typo_spacing_unit":"","ocean_menu_link_color":"","ocean_menu_link_color_hover":"","ocean_menu_link_color_active":"","ocean_menu_link_background":"","ocean_menu_link_hover_background":"","ocean_menu_link_active_background":"","ocean_menu_social_links_bg":"","ocean_menu_social_hover_links_bg":"","ocean_menu_social_links_color":"","ocean_menu_social_hover_links_color":"","ocean_disable_title":"default","ocean_disable_heading":"default","ocean_post_title":"","ocean_post_subheading":"","ocean_post_title_style":"","ocean_post_title_background_color":"","ocean_post_title_background":0,"ocean_post_title_bg_image_position":"","ocean_post_title_bg_image_attachment":"","ocean_post_title_bg_image_repeat":"","ocean_post_title_bg_image_size":"","ocean_post_title_height":0,"ocean_post_title_bg_overlay":0.5,"ocean_post_title_bg_overlay_color":"","ocean_disable_breadcrumbs":"default","ocean_breadcrumbs_color":"","ocean_breadcrumbs_separator_color":"","ocean_breadcrumbs_links_color":"","ocean_breadcrumbs_links_hover_color":"","ocean_display_footer_widgets":"default","ocean_display_footer_bottom":"default","ocean_custom_footer_template":"","ocean_post_oembed":"","ocean_post_self_hosted_media":"","ocean_post_video_embed":"","ocean_link_format":"","ocean_link_format_target":"self","ocean_quote_format":"","ocean_quote_format_link":"post","ocean_gallery_link_images":"on","ocean_gallery_id":[],"footnotes":""},"categories":[2],"tags":[],"class_list":["post-1799","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-information-security","entry","has-media"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/posts\/1799"}],"collection":[{"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/comments?post=1799"}],"version-history":[{"count":6,"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/posts\/1799\/revisions"}],"predecessor-version":[{"id":1815,"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/posts\/1799\/revisions\/1815"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/media\/1810"}],"wp:attachment":[{"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/media?parent=1799"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/categories?post=1799"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/tags?post=1799"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}