<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Victor Nascimento</title>
    <description>The latest articles on DEV Community by Victor Nascimento (@victorwm).</description>
    <link>https://dev.to/victorwm</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1048428%2F13886f60-0f4a-41ed-9c86-cbfa53a3943a.jpeg</url>
      <title>DEV Community: Victor Nascimento</title>
      <link>https://dev.to/victorwm</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/victorwm"/>
    <language>en</language>
    <item>
      <title>How a kid* trivially bypassed a dumb front-end protection</title>
      <dc:creator>Victor Nascimento</dc:creator>
      <pubDate>Sat, 25 Mar 2023 12:48:58 +0000</pubDate>
      <link>https://dev.to/victorwm/how-i-trivially-bypassed-a-dumb-front-end-protection-173n</link>
      <guid>https://dev.to/victorwm/how-i-trivially-bypassed-a-dumb-front-end-protection-173n</guid>
      <description>&lt;h5&gt;
  
  
  *the author called me a kid in one of his passive-aggressive comments.
&lt;/h5&gt;

&lt;p&gt;In this post you will see why security should be taken seriously and why rolling your own security mechanisms instead of relying on industry standards is outright bad.&lt;/p&gt;

&lt;p&gt;This is a post-response to &lt;a href="https://dev.to/matpk/cryptographically-protecting-your-spa-fga"&gt;https://dev.to/matpk/cryptographically-protecting-your-spa-fga&lt;/a&gt; which claims securing server responses with an RSA signature is secure enough to prevent terrible API design from being exploited.&lt;/p&gt;

&lt;p&gt;In the article, the author provides a sample application which I will be using as my exploitation target. This is how it looks like: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oHW4SGwH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5guclog4b83htr62hsmc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oHW4SGwH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5guclog4b83htr62hsmc.png" alt="Image description" width="880" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The name "John Doe" comes from an API response to &lt;code&gt;/users&lt;/code&gt; and as you can see, it contains a signature that, in theory, would prevent a man-in-the-middle attack from modifying it. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w_vrI25t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/918gfhptsdjthz7qcl4d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w_vrI25t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/918gfhptsdjthz7qcl4d.png" alt="Image description" width="771" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Well, let's try... Let's analyze the application source code to see what we can find.&lt;/p&gt;

&lt;p&gt;We see the hardcoded public key:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oGHZwUyn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sn1es2250c1kl3m9dd5r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oGHZwUyn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sn1es2250c1kl3m9dd5r.png" alt="Image description" width="686" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We see the effect calling the &lt;code&gt;/users&lt;/code&gt; API and passing the response through the validation function:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WI8j06hp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wf4mswiwrff5o4wol5bl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WI8j06hp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wf4mswiwrff5o4wol5bl.png" alt="Image description" width="579" height="197"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the validation function itself:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sIac1fVI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8mnhbwis8wviuc3h8y22.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sIac1fVI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8mnhbwis8wviuc3h8y22.png" alt="Image description" width="600" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Man-in-the-middle attack
&lt;/h2&gt;

&lt;p&gt;I have setup Charles proxy, an easy to use network debugging / tampering tool that will allow us to modify the network response. &lt;br&gt;
&lt;a href="https://www.charlesproxy.com/documentation/getting-started/"&gt;https://www.charlesproxy.com/documentation/getting-started/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Charles allows you to intercept and modify network request/responses. Unfortunately MacOS seems to be configured to not allow us to proxy requests from &lt;code&gt;localhost&lt;/code&gt; and it provides &lt;code&gt;localhost.charlesproxy.com&lt;/code&gt; instead which maps directly to 127.0.0.1. Running the application with &lt;code&gt;localhost.charlesproxy.com:3000&lt;/code&gt; produces an error, as &lt;code&gt;crypto&lt;/code&gt; APIs, for obvious reasons, only run on HTTPS or the special &lt;code&gt;localhost&lt;/code&gt; host.  &lt;/p&gt;

&lt;p&gt;But we can fix that and it turns out we don't need to access &lt;code&gt;crypto&lt;/code&gt; at all for this to work. &lt;/p&gt;

&lt;p&gt;Meet our new friend, Chrome devtools overrides. With it we can actually make changes to the code and it will run with our changes. Beautiful. Our first attack to the front-end is to modify the validation function to always return &lt;code&gt;true&lt;/code&gt; regardless of what the signature was:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G1l5VhS4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ns3cmkodm0ox6tcbfjys.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G1l5VhS4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ns3cmkodm0ox6tcbfjys.png" alt="Image description" width="880" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note the application still runs and presents the network response correctly. Now we can actually modify the server response to whatever we want. In Charles you can do that by using the Breakpoints tool: &lt;a href="https://www.charlesproxy.com/documentation/proxying/breakpoints/"&gt;https://www.charlesproxy.com/documentation/proxying/breakpoints/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can set a breakpoint into &lt;code&gt;/users&lt;/code&gt; by enabling the Breakpoints tool and once you hit that request Charles will pause it with this screen which allows you to modify the response:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JV_up8Hy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p2u3rnvic68ghd3y8nu5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JV_up8Hy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p2u3rnvic68ghd3y8nu5.png" alt="Image description" width="880" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And we're done:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CyROaJW0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/83zca202r6f0kfhtyq3k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CyROaJW0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/83zca202r6f0kfhtyq3k.png" alt="Image description" width="880" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The client is completely oblivious of signatures as we just return &lt;code&gt;true&lt;/code&gt; from the function that verifies them. The client is also completely oblivious of network modifications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Don't assume your server is secure just because you thought hardening your front-end was a good idea. Don't reinvent the wheel in terms of security... industry standards are standards because they work and trying to come up with your own "secure" ways will simply not work.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>security</category>
    </item>
  </channel>
</rss>
