<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Surabhi's Blog]]></title><description><![CDATA[Surabhi's Blog]]></description><link>https://surabhisuman.in</link><generator>RSS for Node</generator><lastBuildDate>Fri, 04 Sep 2026 20:41:54 GMT</lastBuildDate><atom:link href="https://surabhisuman.in/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Winning wmn; 2023]]></title><description><![CDATA[Ah! This one has been pending on me for a long time. But as the cozy winters and holiday season are here I felt to wrap up things I wanted to finish this year. After all this year I was trying to push my boundaries and put myself in challenging situa...]]></description><link>https://surabhisuman.in/winning-wmn-2023</link><guid isPermaLink="true">https://surabhisuman.in/winning-wmn-2023</guid><dc:creator><![CDATA[Surabhi Suman]]></dc:creator><pubDate>Tue, 19 Dec 2023 09:52:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1702895191367/85987e3b-83e6-4683-8102-d1ec5ece0e60.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Ah! This one has been pending on me for a long time. But as the cozy winters and holiday season are here I felt to wrap up things I wanted to finish this year. After all this year I was trying to push my boundaries and put myself in challenging situations. Putting my ideas and learnings into blogs also being one :p. Another such experiment was participating in a hackathon with no prep beforehand.</p>
<p><strong>What was the challenge for me?</strong></p>
<p>I'm mostly an introvert person and to speak up in front of even 10 people is daunting for me. Participating in a hackathon where I'll need to brainstorm ideas with unknown folks would be a bit outside my comfort zone. I had participated in hackathons during my undergrad days but had mostly worked alongside my college friends. Nonetheless, I channeled my inner coder strength to convince myself to participate and meet some tech-savvy women in the process. Yep, that was the motivation! :)</p>
<p><strong>What was wmn;2023?</strong></p>
<p>It was an onsite women only 24 hour long hackathon organised by Devfolio.</p>
<p><strong>Ideation Phase</strong></p>
<p>I was working at an insure-tech company back then and had some understanding of problems faced by Indian insurance companies and the gaps in customer expectations and insurance limitations while I was very impressed with the insurance systems in first world countries like Singapore. I thought of building a project on a similar idea. At the hackathon, I met a girl working in healthcare and we brainstormed our ideas for the prototype.</p>
<p><strong>What did we build?</strong></p>
<p>The idea was to solve the overall claims experience at the provider end i.e. insurance providers to be able to detect fraudulent claims and reject them as well as ensure an entire cashless flow from the customer's end without the manual intervention for customers to preserve the receipts from the consultation/treatment and uploading it later to get a reimbursement.</p>
<p><strong>How was it solving the provider experience?</strong></p>
<p>One of the major pain point of an insurance provider is to be able to detect a fraudulent claim. Especially in OPDs with low ticket size, the possibility of fraud increases even more and that is one of the reasons why insurance providers in India don't go for OPD included in the benefits. Another problem is data not being shared by different providers leads to a chance of duplicate claims.</p>
<p><strong>How was it solving customers' experience?</strong></p>
<p>OPD coverage - Most insurance providers in India do not provide OPD coverage. However, from the customers' point of view, this is the biggest economic cost center in health. With lesser possibility of frauds, insurance providers will be able to offer more holistic coverage including OPDs.</p>
<p>Cashless experience - Most of the insurances have a reimbursement flow and no coverage for OPD which leads to saving all the receipts, uploading them, and waiting for weeks for it to be approved.</p>
<p>Privacy of PII data - If there is a central system for storing all the health records, as a customer I should be able to control that data access. Each time an insurer requests my data, I should be able to control what document data I want to share, and only upon my authorization should that data be shared.</p>
<p><strong>Demo link</strong></p>
<p>Adding a demo link for the project -<br />Video - <a target="_blank" href="https://www.loom.com/share/5d235242d6f14470ba1bbcb7830a8c96?sid=48fdd704-788b-4b80-82b4-d1cb63490b72">https://www.loom.com/share/5d235242d6f14470ba1bbcb7830a8c96?sid=48fdd704-788b-4b80-82b4-d1cb63490b72</a><br />Project link - <a target="_blank" href="https://devfolio.co/projects/insurease-50a3">https://devfolio.co/projects/insurease-50a3</a></p>
<p><strong>Winning the grand prize</strong></p>
<p>And yeah that was it. After a really long time, I pushed myself to stay up for ~30 hrs to finish the prototype project as a solo developer. After all, it was about pushing my boundaries. I saw the announcement on <a target="_blank" href="https://twitter.com/devfolio/status/1662850555012866048">twitter</a> the next day. :)</p>
]]></content:encoded></item><item><title><![CDATA[CORS and Effect: HTTP Headers, Cross-Origin Style]]></title><description><![CDATA[CORS refers to Cross-Origin Resource Sharing. It’s a terminology used in the context of browser requests. Now before we get deeper into CORS, we first need to understand origin and why the need for CORS
Origin and same origin policy
Origin is the sou...]]></description><link>https://surabhisuman.in/cors</link><guid isPermaLink="true">https://surabhisuman.in/cors</guid><category><![CDATA[CORS]]></category><category><![CDATA[CORS ERRORS]]></category><category><![CDATA[websecurity]]></category><category><![CDATA[HTTP security headers]]></category><dc:creator><![CDATA[Surabhi Suman]]></dc:creator><pubDate>Mon, 18 Dec 2023 10:43:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1702896107213/d495b129-29ad-4de8-abea-a38671db6a4d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>CORS refers to Cross-Origin Resource Sharing. It’s a terminology used in the context of browser requests. Now before we get deeper into CORS, we first need to understand origin and why the need for CORS</p>
<h3 id="heading-origin-and-same-origin-policy">Origin and same origin policy</h3>
<p>Origin is the source of a particular web request, where the request is originated or is being executed.</p>
<h3 id="heading-what-qualifies-as-the-same-origin">What qualifies as the same origin?</h3>
<p>Two URLs have the same origin if they have the same</p>
<ol>
<li><p>protocol</p>
</li>
<li><p>domain</p>
</li>
<li><p>port</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702883010007/d6c0a4f4-a635-4b33-95ef-bf76d79cb3a5.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
<p>Below URLs qualify as having the same origin as the above highlighted URL</p>
<ol>
<li><p><a target="_blank" href="https://www.google.com/maps">http://www.google.com:443/maps</a></p>
</li>
<li><p><a target="_blank" href="https://www.google.com/maps">https://www.gooogle.com/foo</a></p>
</li>
</ol>
<p>Below URLs do not qualify as the same origin as the above highlighted URL</p>
<ol>
<li><p><a target="_blank" href="https://www.google.com/maps">http://www.google.com/maps</a> - Different protocol</p>
</li>
<li><p><a target="_blank" href="https://www.google.com/maps">https://google.com/maps</a> - Different domain</p>
</li>
<li><p><a target="_blank" href="https://www.google.com/maps">https://ww.google.com:8080/maps</a> - Different port</p>
</li>
</ol>
<h3 id="heading-same-origin-policy">Same origin policy</h3>
<p>To prevent different sites from accessing each other’s data (cookies, web storage, run scripts), same-origin policy is enforced by web browsers, and its enforcement dates back to 1996. This policy controls interaction between two origins when using HTTP requests. If you try accessing another origin, you’ll get a CORS error. In modern web browsers, CORS is disabled by default.</p>
<p><strong>Let’s try this out!</strong> ✨</p>
<p>First, we’ll open dev tools on any website. Currently, I’m on <a target="_blank" href="https://www.google.com/maps">https://www.google.com</a> and let’s also spawn a node web server.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>)
<span class="hljs-keyword">const</span> app = express()
<span class="hljs-keyword">const</span> port = <span class="hljs-number">3000</span>

app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">'Hello World!'</span>);
})

app.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Example app listening on port <span class="hljs-subst">${port}</span>`</span>)
})
</code></pre>
<p>Now I have a NodeJS server running on port 3000.</p>
<p>We’ll make a simple fetch call in the browser console to get the response from our server.</p>
<pre><code class="lang-jsx">fetch(<span class="hljs-string">"&lt;http://localhost:3000&gt;"</span>).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.text()).then(<span class="hljs-function"><span class="hljs-params">x</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(x));
</code></pre>
<p>On executing this, we got an error like this</p>
<pre><code class="lang-jsx">Access to fetch at <span class="hljs-string">'&lt;http://localhost:3000/&gt;'</span> <span class="hljs-keyword">from</span> origin <span class="hljs-string">'&lt;https://www.google.com&gt;'</span> has been blocked by CORS policy:
No <span class="hljs-string">'Access-Control-Allow-Origin'</span> header is present on the requested resource. 
If an opaque response serves your needs, set the request<span class="hljs-string">'s mode to '</span>no-cors<span class="hljs-string">' to fetch the resource with CORS disabled.</span>
</code></pre>
<p>and if we check the network tab, we see the following error</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702883161555/851d3e19-1909-4e70-94b0-952ef19ebcdf.png" alt /></p>
<p>The error says we cannot access <a target="_blank" href="https://www.google.com/maps">http://localhost:3000</a> as the origins mismatch and the server running at <a target="_blank" href="https://www.google.com/maps">localhost</a> should allow requests coming from the origin <a target="_blank" href="https://www.google.com/maps">https://www.google.com</a> in order for us to proceed.</p>
<p>Let’s make a few tweaks to our application code</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>)
<span class="hljs-keyword">const</span> app = express()
<span class="hljs-keyword">const</span> port = <span class="hljs-number">3000</span>

app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.setHeader(<span class="hljs-string">'Access-Control-Allow-Origin'</span>, <span class="hljs-string">'&lt;https://www.google.com&gt;'</span>);
  res.send(<span class="hljs-string">'Hello World!'</span>);
})

app.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Example app listening on port <span class="hljs-subst">${port}</span>`</span>)
})
</code></pre>
<p>and try making the same simple fetch call in the browser console.</p>
<p>Voila! 💫 It worked. We got a response.</p>
<pre><code class="lang-jsx"><span class="hljs-built_in">Promise</span> {<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">pending</span>&gt;</span>}
Hello World!</span>
</code></pre>
<p>Note that we added a special header <code>[Access-Control-Allow-Origin](&lt;</code><a target="_blank" href="https://www.google.com/maps"><code>https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin</code></a><code>&gt;)</code> to response headers. and we set its value to <a target="_blank" href="https://www.google.com/maps"><code>https://www.google.com</code></a>. This is a way for the server to tell the browser that it trusts requests coming from <code>[&lt;</code><a target="_blank" href="https://www.google.com/maps"><code>https://www.gooogle.com&gt;](&lt;https://www.gooogle.como</code></a><code>&gt;)</code> origin. We can also set the value of this header to “<code>*</code> ” wildcard which means it can allow requests from any origin and not just <a target="_blank" href="https://www.google.com/maps">google.com</a>.</p>
<p>Now let’s try something fancy! Let’s add a custom header to our simple fetch request</p>
<pre><code class="lang-jsx">fetch(<span class="hljs-string">"&lt;http://localhost:3000&gt;"</span>, {<span class="hljs-attr">headers</span>: {<span class="hljs-string">'a'</span>: <span class="hljs-string">'b'</span>}})
.then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.text())
.then(<span class="hljs-function"><span class="hljs-params">x</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(x));
</code></pre>
<p>Oops! We’re again getting the CORS error</p>
<pre><code class="lang-jsx">Access to fetch at <span class="hljs-string">'&lt;http://localhost:3000/&gt;'</span> <span class="hljs-keyword">from</span> origin <span class="hljs-string">'&lt;https://www.google.com&gt;'</span> has been blocked by CORS policy: 
Response to preflight request doesn<span class="hljs-string">'t pass access control check: 
No '</span>Access-Control-Allow-Origin<span class="hljs-string">' header is present on the requested resource. 
If an opaque response serves your needs, set the request'</span>s mode to <span class="hljs-string">'no-cors'</span> to fetch the resource <span class="hljs-keyword">with</span> CORS disabled.
</code></pre>
<blockquote>
<p>An opaque response is a type of response that doesn't allow the web page to access the response's data, headers, or status.</p>
</blockquote>
<p>Note that my emphasis was on <code>simple fetch request</code>. Read more about simple requests <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests">here</a>. We made it fancy by adding a custom header to it. This simple request does not trigger a CORS preflight request. Oh! again a fancy term <strong>preflight request.</strong> Let’s get into that!</p>
<blockquote>
<p>A <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request">preflight request</a> is an OPTIONS request automatically made by the browser to check if the server is ready to accept the actual request, headers and allows the request from the given origin. This is a lightweight request and server usually responds with 204 No content if it agrees to the request conditions or can return an error. It is not triggered for simple requests.</p>
</blockquote>
<p>Since our <code>app.js</code> does not have handling for that OPTIONS request, it is throwing the error. Let’s fix that</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>)
<span class="hljs-keyword">const</span> app = express()
<span class="hljs-keyword">const</span> port = <span class="hljs-number">3000</span>

app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.setHeader(<span class="hljs-string">'Access-Control-Allow-Origin'</span>, <span class="hljs-string">'&lt;https://www.google.com&gt;'</span>);
  res.send(<span class="hljs-string">'Hello World!'</span>);
})

app.options(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.setHeader(<span class="hljs-string">'Access-Control-Allow-Origin'</span>, <span class="hljs-string">'&lt;https://www.google.com&gt;'</span>);
  res.setHeader(<span class="hljs-string">'Access-Control-Allow-Headers'</span>, <span class="hljs-string">'a'</span>);
  res.sendStatus(<span class="hljs-number">204</span>);
})

app.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Example app listening on port <span class="hljs-subst">${port}</span>`</span>)
})
</code></pre>
<p>Note that we also added a response header to allow the custom header without which we’d again be getting CORS error.</p>
<p>Now if we hit our <a target="_blank" href="https://www.notion.so/CORS-0456ec07e7cc48ef871cef670ab793c3?pvs=21">fancy fetch request</a> again, we’d notice that there are two requests that browser sent to the server. One was the OPTIONS request for which it got the below response</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702883183142/be5c02d0-8080-46cf-af91-0499b8cfdbb0.png" alt /></p>
<p>Here we can see that the server has allowed the origin and also the custom header.</p>
<p>and we got the 200 OK response for the GET request</p>
<pre><code class="lang-jsx"><span class="hljs-built_in">Promise</span> {<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">pending</span>&gt;</span>}
Hello World!</span>
</code></pre>
<h2 id="heading-how-to-block-cross-origin-access">How to block cross origin access</h2>
<p><a target="_blank" href="https://www.google.com/maps">https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#how_to_block_cross-origin_access</a></p>
<p>This is particularly useful in avoiding CSRF attacks.</p>
<h2 id="heading-how-to-allow-cross-origin-access">How to allow cross origin access</h2>
<ul>
<li><p><strong>Using the</strong> <code>Access-Control-Allow-Origin</code> header</p>
</li>
<li><p><strong>Changing origins</strong></p>
<p>  Some browsers provide the capability to change domain so that the requester can pose as the same domain and request can go through without the CORS error. However, this is limited to superdomains of the current domain only.</p>
<p>  For e.g. I can change document domain for <a target="_blank" href="https://www.google.com/maps">https://foo.bar.com</a> to <a target="_blank" href="https://www.google.com/maps">https://bar.com</a> by doing this on <a target="_blank" href="https://www.google.com/maps"><code>https://foo.bar.com</code></a></p>
<pre><code class="lang-jsx">  <span class="hljs-built_in">document</span>.domain = <span class="hljs-string">'&lt;https://bar.com&gt;'</span>
</code></pre>
<p>  But I cannot change it to <a target="_blank" href="https://www.google.com/maps"><code>http://localhost:3000</code></a> [Not a superdomain]</p>
<p>  Google chrome has deprecated this citing security reasons, but Safari allows it.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702883198775/a7f16446-9442-4714-b996-44329e2d724a.png" alt="Safari" /></p>
</li>
<li><p><strong>PostMessage</strong></p>
</li>
</ul>
<p><a target="_blank" href="https://www.google.com/maps">https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage</a></p>
]]></content:encoded></item><item><title><![CDATA[XSS Demystified: Understanding and Preventing Cross-Site Scripting]]></title><description><![CDATA[It allows an attacker to execute a malicious arbitrary Javascript code within the web browser of victim user. This gives the attacker’s script privileged access to make requests to the server (such as same-origin cookies and storage permissions) and ...]]></description><link>https://surabhisuman.in/xss</link><guid isPermaLink="true">https://surabhisuman.in/xss</guid><category><![CDATA[XSS]]></category><category><![CDATA[websecurity]]></category><dc:creator><![CDATA[Surabhi Suman]]></dc:creator><pubDate>Mon, 18 Dec 2023 06:45:24 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1702883300996/3ad1c7f2-f65c-4f64-afba-edcdcf7022c9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It allows an attacker to execute a malicious arbitrary Javascript code within the web browser of victim user. This gives the attacker’s script privileged access to make requests to the server (such as same-origin cookies and storage permissions) and steal data.</p>
<h3 id="heading-examples">Examples</h3>
<p>Let’s say a vulnerable social media website allows html content in an input field. An attacker can enter malicious html in that input field. This script which will be executed every time any user of the vulnerable website visits that page. Such type of attack can impact mass users with a single attack.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702880567272/586f95cd-1064-4f17-b948-9a28c543c63e.png" alt /></p>
<p>In this particular example whenever John or Alice load their timeline, the script <code>authstealer.js</code> will automatically run in their browsers and Evil will get access to their session data and compromised accounts. Evil can now login to John and Alice’s accounts and see their payment information, PII data etc.</p>
<h3 id="heading-lets-try-xss">Let’s try XSS! ✨</h3>
<p>We’ll just create a simple NodeJS server, and a basic HTML and try injecting some JS into that</p>
<p>Here’s my <code>index.html</code></p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Enter your name<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"name"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">input</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"addData()"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"test.js"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">br</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">br</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"self-xss"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<pre><code class="lang-jsx"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addData</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> name = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'name'</span>).value;
    <span class="hljs-keyword">const</span> parsedDocument = <span class="hljs-built_in">document</span>.createRange().createContextualFragment(name);
    <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'self-xss'</span>).appendChild(parsedDocument);
}
</code></pre>
<p>which renders a web page like this. This website has an input field that takes input names and displays them in a div.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702880600688/12aca8a4-92ce-4dc6-a051-e7b2063f89f3.png" alt /></p>
<p>Now, we’ll try doing something evil 😈. Instead of entering any text name, we’ll try injecting a script in the input field here</p>
<p>which is as simple as <code>&lt;script&gt;alert("XSS attack")&lt;/script&gt;</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702880610284/a0bb1eca-9b6f-42b1-b220-9d967565e09b.png" alt /></p>
<p>What happened here is instead of listing down the input, the script got executed here. And instead of that simple script, I can have the script downloaded from some other source and try to steal the credentials and session data of logged-in user here.</p>
<h3 id="heading-how-to-prevent-xss">How to prevent XSS?</h3>
<ol>
<li><p><strong>Safely Validating input fields</strong> - Mostly websites allow very limited set of HTML markup or do not allow HTML markup at all in input fields.</p>
</li>
<li><p><strong>HTTP only cookie</strong> - This makes cookies unavailable to client side scripts.</p>
</li>
<li><p>Disable JavaScript in browsers. But that would make our website unresponsive. We’ll just be able to load static HTML pages. This might work for some use cases where we have just static HTML websites.</p>
</li>
<li><p>Send a request header <code>'X-XSS-PROTECTION'</code> and its value can be set to none or some origin value stating that it will accept scripts only from a particular origin. Please note that this also disables inline scripting in html pages.</p>
</li>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value">SameSite cookie parameter</a></p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Deciphering CSRF]]></title><description><![CDATA[CSRF refers to cross-site request forgery. It is an exploit on websites where an attacker is forging the identity of a trusted user to perform an action that the user didn’t intend to.
Who is a trusted user?
A trusted user for a website can be an aut...]]></description><link>https://surabhisuman.in/csrf</link><guid isPermaLink="true">https://surabhisuman.in/csrf</guid><category><![CDATA[csrf]]></category><category><![CDATA[cloud security]]></category><category><![CDATA[CORS]]></category><dc:creator><![CDATA[Surabhi Suman]]></dc:creator><pubDate>Mon, 18 Dec 2023 06:16:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1702880044940/0c0cdc39-9d39-45dc-a79c-4cf1f9cc4dfc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>CSRF refers to cross-site request forgery. It is an exploit on websites where an attacker is forging the identity of a trusted user to perform an action that the user didn’t intend to.</p>
<h3 id="heading-who-is-a-trusted-user">Who is a trusted user?</h3>
<p>A trusted user for a website can be an authenticated user with valid session data. The attack gets worse if the trusted user has administrative privileges to the website.</p>
<h3 id="heading-how-it-works">How it works?</h3>
<p>The attacker poses as the trusted user (who is unaware of the ill intention of the attacker) to perform an action and it mostly tries to alter the state of website’s backend data. The attacker executes this action via social engineering e.g. a hidden link in email which when clicked executes the script or hidden link in img tag which does not even require user to click any link but will be executed as soon as the page is loaded. It may look like this</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">'&lt;https://yourbank.com?payeeId=evil&amp;amount=10000&gt;'</span> <span class="hljs-attr">height</span>=<span class="hljs-string">0,</span> <span class="hljs-attr">width</span>=<span class="hljs-string">0</span>&gt;</span>
</code></pre>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">'&lt;https://yourbank.com?payeeId=evil&amp;amount=10000&gt;'</span>&gt;</span> View Cute Pictures! <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<p>or some POST request like this</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"&lt;https://yourbank.com/transfer&gt;"</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"POST"</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"hidden"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"acct"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"EVIL"</span>/&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"hidden"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"amount"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"10000"</span>/&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"View my pictures"</span>/&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<p>or PUT</p>
<pre><code class="lang-jsx">&lt;script&gt;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">put</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">var</span> x = <span class="hljs-keyword">new</span> XMLHttpRequest();
    x.open(<span class="hljs-string">"PUT"</span>,<span class="hljs-string">"&lt;http://yourbank.com/transfer&gt;"</span>,<span class="hljs-literal">true</span>);
    x.setRequestHeader(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"application/json"</span>);
    x.send(<span class="hljs-built_in">JSON</span>.stringify({<span class="hljs-string">"acct"</span>: <span class="hljs-string">"EVIL"</span>, <span class="hljs-string">"amount"</span>:<span class="hljs-number">10000</span>})); 
}
&lt;/script&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">body</span> <span class="hljs-attr">onload</span>=<span class="hljs-string">"put()"</span>&gt;</span></span>
</code></pre>
<p>Web browsers by default send all the cookies and session data of the domain website when the request is made to that website. So when the request is executed by the trusted user (unknowingly) the vulnerable receiver website will validate the session data and allow the request to go through.</p>
<h2 id="heading-how-to-prevent-csrf">How to prevent CSRF?</h2>
<ol>
<li><p><strong>Disabling CORS</strong> - Most modern browsers disable CORS by default which means cross origin requests won’t go through. However, attack can still happen if the target website has enabled CORS by putting <code>*</code> in <code>'Access-Control-Allow-Origin'</code> header.</p>
</li>
<li><p><strong>'X-CSRF-TOKEN’</strong> - Setting this token explicitly in headers. Backend server can generate a token (random and time based) and send it to the client in response cookies for preflight request. Client can parse the cookie and set the header while making a new request to backend server. This token should be a random and unique value with expiry for each request. However, this approach is based on the fact that the attacker script is unable to read the response cookies and set the header parameter.</p>
</li>
<li><p><strong>Checking the referrer header</strong> (Origin/Referer header)- Backend server should always check if the referrer is a domain other than the one they intended to allow and block such requests from going to the application servers. Reliability on these headers comes from the fact that they cannot be altered programmatically as they fall under <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name">forbidden headers</a> list, meaning that only the browser can set them.</p>
</li>
<li><p><strong>SameSite cookie attribute</strong> - Setting this cookie value to <code>Lax</code>, <code>Strict</code>, or <code>None</code> . This attribute helps the browser decide whether to send cookies along with cross-site requests.</p>
</li>
<li><p><strong>Do not use GET requests for state changing operations.</strong></p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Logging in Microservices: A developer's journey]]></title><description><![CDATA[As software engineers, logs are our best friend for finding anything right/wrong with our services. Be it exception tracing, RCA for a bug, consumer claims, or user journey, logs are the tool to trace it. Yet, I feel as software engineers, we do not ...]]></description><link>https://surabhisuman.in/logging-in-microservices</link><guid isPermaLink="true">https://surabhisuman.in/logging-in-microservices</guid><category><![CDATA[logging]]></category><category><![CDATA[Microservices]]></category><category><![CDATA[monitoring]]></category><dc:creator><![CDATA[Surabhi Suman]]></dc:creator><pubDate>Thu, 14 Dec 2023 14:11:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1702563053463/26723d60-58ec-4347-83be-464dea532976.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As software engineers, logs are our best friend for finding anything right/wrong with our services. Be it exception tracing, RCA for a bug, consumer claims, or user journey, logs are the tool to trace it. Yet, I feel as software engineers, we do not pay much attention to log management while developing applications (right from putting them into application code properly in the first place). This article is not about the best tools you can have for log management for your application but some stuff that you can keep in mind for having the right log management for your application.</p>
<p>An ideal log may look like:</p>
<blockquote>
<p><strong><em>log(level: “error”, trace_id: “”, message: “Custom error message with context”, data: {“host-name”: “”, “host-ip”: “”, “contextual-key”: “contextual-value”}, timestamp: “”, stacktrace: “”)</em></strong></p>
</blockquote>
<h2 id="heading-why-a-proper-logging-is-needed"><strong>Why a proper logging is needed?</strong></h2>
<ol>
<li><p>Well, first and foremost we all make mistakes. Having a logging system with stack trace, log levels, contextual data, and errors (if any) can help us identify an issue in no time.</p>
</li>
<li><p>It is great for collaboration and having to work with multiple team members (unless you wanna remain the forever on-call person 😛). It’s helpful for a new person who gets onboarded to your service to understand the errors/context easily.</p>
</li>
<li><p>Logs help in tracking your user journey and identifying issues. (P.S. You can set up alerting and monitoring on top of your logs/some log patterns too. I have done it in the past and it was super helpful.)</p>
</li>
</ol>
<h2 id="heading-logs-delivery-where-can-you-store-your-logs"><strong>Logs delivery (Where can you store your logs?)</strong></h2>
<ul>
<li><p><strong>Console output</strong> — Very common and basic logging strategy for debugging. This is very simple and easy to use and handy when developing an application. Cons — logs won’t persist after the console is closed.</p>
</li>
<li><p><strong>File write</strong> — Your application can keep writing logs to a file, and so the log events will be stored on a local disk. And they’ll persist even if you close the console. However one issue that it may lead to is fast utilization of disk space on your application server.</p>
</li>
<li><p><strong>HTTP</strong> — You can make an HTTP call to your log service with the log payload and it’s up to the log service to process and store it the way it wants (well, the way it’s configured rather 😅). But this leads to a whole new set of issues, i.e delay in application response time. If you add too many logs to your application and it makes a synchronous HTTP call to log service every time, it’ll add a lot of delay in your application response time because of HTTP encryption/decryption/authentication/acknowledgment (and who doesn’t want a faster response time for their application).<br />  ▹ <strong>Solution —</strong> Make asynchronous calls. Yes, I’m coming to the downside for this too, don’t be judgemental so soon. Making asynchronous calls on a separate thread to the log service does solve one problem of delay in application response time. But, what about retries? What if your async HTTP call to log service fails and your application crashes too! Imagine having to debug the cause of the application crash when your error logging call failed too :(.<br />  You can go for a hybrid approach, wherein for the severe logs, you make sync calls to log service (ERROR level log for e.g.) and for debug/verbose you can make async calls.</p>
</li>
<li><p><strong>Queueing</strong> — You can push log messages to a queue and they can be processed later, in batches or as single events, like a Kafka streaming platform. You can build a retry mechanism on top of it too.</p>
</li>
</ul>
<p>You may go for a combination of these depending upon the requirements. For e.g. can write logs to a local disk and other software reading that file at frequent intervals and push it to the log service (something like <a target="_blank" href="https://linux.die.net/man/8/logrotate">logRotate</a>).</p>
<h2 id="heading-some-tips"><strong>Some tips</strong></h2>
<ul>
<li><p>Add a uniform source ID especially if you’re working with microservices. What that means is you generate a request ID/UUID for a new request that comes from the client and you tag all the logs that are generated across different microservices throughout this request lifecycle with this unique id. This comes in handy when you want to track the user behavior/abnormality across microservices.</p>
</li>
<li><p>Always add log severity very literally to the context of why you’ve added a particular log. There are 4 log levels, DEBUG, INFO, WARNING, and ERROR. One common mistake people make is adding everything to an INFO level log. Adding logs without the proper level may lead to chaos and you may not find the actual log that you’re looking for in times of crisis.</p>
</li>
<li><p>Make sure to add timestamp at the application level to track the exact timestamp of the event. If you add timestamp of log entry, it may not respresent the actual timestamp of event as there could be some delay in log registration.</p>
</li>
<li><p>Find a tool for centralizing your logs.<br />  ▹ If you’re working with distributed systems, you’ll likely have logs on different servers, which may be spread across different microservices, and fragmented. Having a centralized tool is very helpful for monitoring and troubleshooting issues in a certain time period.<br />  ▹ Look out for tools that allow you to filter, query, index, and search data according to your needs because you cannot always work with plain text logs.<br />  ▹ Check support for multiline logs. If you have stored stack traces in error logs and your logging software treats each line as a separate log, it becomes super confusing to look at.</p>
</li>
<li><p>Don’t forget to remove business info-related logs while creating a release build.</p>
</li>
</ul>
<p>Really, in the end, it should be you deciding what to use for your application. There’s no need to over-engineer your logging system (any software actually 😅)if your system doesn’t have the requirement for that.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding Bloom Filter]]></title><description><![CDATA[It is a probabilistic space-efficient data structure with O(1) insertion and retrieval. It is used to find if a key exists (with false positives) or not (no false negatives). It can be used as a data layer to check if a key exists before querying the...]]></description><link>https://surabhisuman.in/understanding-bloom-filter</link><guid isPermaLink="true">https://surabhisuman.in/understanding-bloom-filter</guid><category><![CDATA[Databases]]></category><category><![CDATA[bloom filter]]></category><category><![CDATA[probabilistic data structure]]></category><dc:creator><![CDATA[Surabhi Suman]]></dc:creator><pubDate>Thu, 14 Dec 2023 13:51:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1702561841170/1392d026-be5f-4144-89b7-40f2476741df.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It is a probabilistic space-efficient data structure with O(1) insertion and retrieval. It is used to find if a key exists (with false positives) or not (no false negatives). It can be used as a data layer to check if a key exists before querying the actual database (expensive read vs cheap read).</p>
<p><strong>Pros</strong>-</p>
<ul>
<li><p>Uses constant space (Space efficient).</p>
</li>
<li><p>O(1) insertion and retrieval</p>
</li>
</ul>
<p><strong>Cons</strong>-</p>
<ul>
<li>False positives. It can not accurately tell if a key exists for sure in the bloom filter. But it can tell if a key does not exist in there.</li>
</ul>
<h3 id="heading-how-it-works">How it works?</h3>
<p>It requires some hash functions and a binary hash table.</p>
<p>First, we set all the bits in hash table to 0</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*2NfgJkCFiubi4t_To_-Oew.png" alt /></p>
<p>Let’s say we have two hash functions H1 and H2</p>
<h3 id="heading-insertion">Insertion:-</h3>
<p>→ Insert “Hello”. H1(“Hello”) = 0, H2(“Hello”) = 3</p>
<p>→ Since bits at 0 and 3 positions are set to 0, we toggle it to 1.</p>
<p>→ Now the hash table looks like this</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*soqd7lcHidICUb_Tj1HxsA.png" alt /></p>
<p>→ Insert “World”. H1(“World”) = 5, H2(“World”) = 3</p>
<p>→ Toggle bits. Now the hash table looks like this</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*osxtq8ZsXJJIHI0WcsPhCQ.png" alt /></p>
<h3 id="heading-searching">Searching:-</h3>
<p>→ Search “World”. H1(“World”) = 5, H2(“World”) = 3.</p>
<p>→ Check bits at 3rd and 5th index. Both are set to 1. So it would return 1. Maybe exists case</p>
<p>→ Search “Foo”. H1(“Foo”) = 0, H2(“Foo”) = 5</p>
<p>→ Check bits at 0th and 5th index. Though it will return 1. But “Foo” does not exist. False positive case.</p>
<h3 id="heading-applications">Applications:-</h3>
<p>It is mostly used in conjugation with primary DB to check if an element is present or not and then search the primary DB. It can be used at places where we are okay with false positives and a quick lookup can save the expensive DB read.</p>
<ul>
<li><p>Used by Medium to show if an article is read by the user.</p>
</li>
<li><p>Malicious sites blocker by Google.</p>
</li>
<li><p>Password and username duplicate check.</p>
</li>
<li><p>Used to show target ads.</p>
</li>
</ul>
<p><strong>Default support with databases</strong></p>
<ul>
<li><p>Postgres — Postgres supports bloom index which is pretty useful for membership check cases. Link — <a target="_blank" href="https://www.postgresql.org/docs/current/bloom.html">https://www.postgresql.org/docs/current/bloom.html</a></p>
</li>
<li><p>Redis — Redis (4.0 +) has ReBloom library which has bloom filter application. Link — <a target="_blank" href="https://www.postgresql.org/docs/current/bloom.html">https://redis.com/blog/bloom-filter/</a></p>
</li>
<li><p>Some databases like HBase and Cassandra by default use bloom filter to filter out queries.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Navigating Database Partitioning with Postgres]]></title><description><![CDATA[Database partitioning in simplest terms refers to dividing a big table into smaller tables for ease of maintenance, query optimization, etc.
Advantages:-

Faster querying - Queries can be parallelly processed for range and aggregate queries and match...]]></description><link>https://surabhisuman.in/navigating-database-partitioning-with-postgres</link><guid isPermaLink="true">https://surabhisuman.in/navigating-database-partitioning-with-postgres</guid><category><![CDATA[Databases]]></category><category><![CDATA[Database Partitioning]]></category><dc:creator><![CDATA[Surabhi Suman]]></dc:creator><pubDate>Thu, 14 Dec 2023 13:18:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1702559713910/1cd69bdb-a9e5-4568-a7ef-05d29bb01f95.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Database partitioning in simplest terms refers to dividing a big table into smaller tables for ease of maintenance, query optimization, etc.</p>
<h3 id="heading-advantages"><strong>Advantages:-</strong></h3>
<ol>
<li><p><strong>Faster querying</strong> - Queries can be parallelly processed for range and aggregate queries and match queries can be worked up with smaller subsets instead of searching in bigger tables thus reducing query time.</p>
</li>
<li><p><strong>Data Archival</strong> - By dividing data into smaller tables, less frequently used or unused partitions can be moved to cheaper storage thus making more room for recent data and optimizing on the costs.</p>
</li>
<li><p><strong>Maintenance</strong> - We can easily run bulk update and drop partition queries without obtaining a global lock on the entire table blocking our read-write operations.</p>
</li>
</ol>
<h3 id="heading-disadvantages"><strong>Disadvantages:-</strong></h3>
<ol>
<li><p><strong>Data updation across partitions</strong> - Data updation becomes tricky especially when updation leads to the movement of table rows from one partition to another. Let’s again take the example of our score table. If update marks for id = 411 from 51 to 98, the said row will need to be transferred from partition score_4060 to score_80100.</p>
</li>
<li><p><strong>Searching via indexes</strong> - If the index key is other than the partition key, maintaining those indexes also becomes a challenge. This becomes more difficult when partitions are separated across nodes (sharding). We can though manage this by maintaining individual indexes at the partition level but if we’ve to search using the index, it will have to search all the indexes and then collate the data before returning to the application or the application will have to maintain this collation for some cases (e.g. inheritance partitioning in postgres). Another solution is to maintain the indexes at partitioned table level and each partition table can keep a copy of the same index.</p>
</li>
</ol>
<h3 id="heading-try-it-out">Try it out ✨</h3>
<p>Let’s try to create a partition table on Postgres database. Please note that the below experiments are being done on Postgres database and the results may vary for other databases.</p>
<p>For this experiment, we can use locally installed Postgres or a docker container. The goal here is to get a postgres server running. We’ll create a table named score having columns id and marks, and partition it by marks.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> score (
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">SERIAL</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    marks <span class="hljs-built_in">INTEGER</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>
) <span class="hljs-keyword">partition</span> <span class="hljs-keyword">by</span> <span class="hljs-keyword">range</span>(marks);
</code></pre>
<p>and create some partitions</p>
<pre><code class="lang-sql"><span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> score_0020 <span class="hljs-keyword">partition</span> <span class="hljs-keyword">of</span> score <span class="hljs-keyword">for</span> <span class="hljs-keyword">values</span> <span class="hljs-keyword">from</span> (<span class="hljs-number">0</span>) <span class="hljs-keyword">to</span> (<span class="hljs-number">20</span>);
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> score_2040 <span class="hljs-keyword">partition</span> <span class="hljs-keyword">of</span> score <span class="hljs-keyword">for</span> <span class="hljs-keyword">values</span> <span class="hljs-keyword">from</span> (<span class="hljs-number">20</span>) <span class="hljs-keyword">to</span> (<span class="hljs-number">40</span>);
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> score_4060 <span class="hljs-keyword">partition</span> <span class="hljs-keyword">of</span> score <span class="hljs-keyword">for</span> <span class="hljs-keyword">values</span> <span class="hljs-keyword">from</span> (<span class="hljs-number">40</span>) <span class="hljs-keyword">to</span> (<span class="hljs-number">60</span>);
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> score_6080 <span class="hljs-keyword">partition</span> <span class="hljs-keyword">of</span> score <span class="hljs-keyword">for</span> <span class="hljs-keyword">values</span> <span class="hljs-keyword">from</span> (<span class="hljs-number">60</span>) <span class="hljs-keyword">to</span> (<span class="hljs-number">80</span>);
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> score_80100 <span class="hljs-keyword">partition</span> <span class="hljs-keyword">of</span> score <span class="hljs-keyword">for</span> <span class="hljs-keyword">values</span> <span class="hljs-keyword">from</span> (<span class="hljs-number">80</span>) <span class="hljs-keyword">to</span> (<span class="hljs-number">100</span>);
</code></pre>
<p>If we check our table is created now</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702557927940/95a7a5be-4c57-4809-8320-a9a3d76461ed.png" alt class="image--center mx-auto" /></p>
<p>Note that the partitioned_table <code>score</code> is just a virtual table with no storage to it. Storage actually belongs to the partition tables <code>score_0020</code>, <code>score_2040</code> and so on.</p>
<p>Let’s seed our database table with some random data</p>
<pre><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> score(marks) 
<span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">floor</span>(random()*<span class="hljs-number">100</span>) 
<span class="hljs-keyword">FROM</span> generate_series(<span class="hljs-number">0</span>,<span class="hljs-number">10000000</span>);
</code></pre>
<p>And we’re done!!</p>
<p><strong>Let’s try out some queries</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702557960972/21e28ae1-94f2-4264-8c6f-202b58b5ca41.png" alt class="image--center mx-auto" /></p>
<p>Let’s also try creating an index on column <code>marks</code></p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">INDEX</span> marks_idx <span class="hljs-keyword">ON</span> score(marks);
</code></pre>
<p>and check for the index status</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702557989744/9ef49d69-c6af-463f-8484-247917c3a400.png" alt class="image--center mx-auto" /></p>
<p>Indexes automatically got created on partition tables as well. And the best part is our application does not need to worry about which partition to query from. PostgreSQL automatically propagates the index to each partition.</p>
<p>If we search for any marks, it went for searching only in the partition <code>score_0020</code> and also utilized the index.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702558149889/7c194eea-02da-441c-9572-84b27ddf5093.png" alt /></p>
<p>Let’s also create an unpartitioned table for benchmarking</p>
<pre><code class="lang-sql"><span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> score_unpartitioned(<span class="hljs-keyword">id</span> <span class="hljs-built_in">serial</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>, marks <span class="hljs-built_in">integer</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> score_unpartitioned(marks) <span class="hljs-keyword">select</span> (random()*<span class="hljs-number">100</span>) <span class="hljs-keyword">from</span> generate_series(<span class="hljs-number">0</span>,<span class="hljs-number">10000000</span>);
<span class="hljs-keyword">create</span> <span class="hljs-keyword">index</span> score_unpartitioned_idx <span class="hljs-keyword">on</span> score_unpartitioned(marks);
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702558181653/81b99906-2511-4412-9782-4d15687d4181.png" alt /></p>
<p>As we can clearly see, query is much faster with the partitioned table in comparison to an unpartitioned table as the query has to search just on the partitioned table.<br />An important point to note however is indexes, partitions and optimisation of queries depend on the size of data that we have and the acceptable response time for the queries that we have and of course, there is the cost factor associated with creating multiple indexes and partitioned tables. Number of partitions and strategy for partition also depends on the size of data and the type of queries that you have to run. YMMV!</p>
]]></content:encoded></item><item><title><![CDATA[Exploring Database Indexes]]></title><description><![CDATA[Why Indexes?
Database indexes are used for faster data retrieval. Let's explore the underlying data structure behind these indexes that enables faster queries.
Hash Index
This is a log based index and probably simpler and easiest to implement. It sto...]]></description><link>https://surabhisuman.in/exploring-database-indexes</link><guid isPermaLink="true">https://surabhisuman.in/exploring-database-indexes</guid><category><![CDATA[Databases]]></category><category><![CDATA[Indexes]]></category><category><![CDATA[binary-indexed-tree]]></category><dc:creator><![CDATA[Surabhi Suman]]></dc:creator><pubDate>Thu, 14 Dec 2023 12:38:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1702557332546/35b4b5d0-076f-4e8b-a733-8e5191a5d3bb.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-why-indexes">Why Indexes?</h3>
<p>Database indexes are used for faster data retrieval. Let's explore the underlying data structure behind these indexes that enables faster queries.</p>
<h3 id="heading-hash-index">Hash Index</h3>
<p>This is a log based index and probably simpler and easiest to implement. It stores data in key value pair format in an append only file. When the file size grows it just moves to storing data in a different file. Compaction happens in the background asynchronously. Compaction is the process of merging two files and using the latest one as the trusted and updated source of data.</p>
<h3 id="heading-sstable">SSTable</h3>
<p>SSTable is Sorted string table. Similar to hash index, it also stores key-value pairs in an append only segment file but in a sorted order sorted by key. Compaction also happens in the background on a regular interval.</p>
<p><strong>How does it maintain sorted order in a segment file?</strong></p>
<p>It uses any sorted data structure like Red Black Tree or AVL tree to keep keys in sorted order.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702555574390/9b16589d-e11d-4cb4-b316-138e61d5e366.png" alt class="image--center mx-auto" /></p>
<p><strong>How compaction works?</strong></p>
<p>SSTable make writes faster by appending data in an append only segment file. On files reaching a certain limit, new writes are done on new segment file. Compaction takes values from latest segment file and rejects values from old segement files in case of repeated keys. Since SSTables are already sorted, merging is faster as well with help of any sorting algorithm like merge sort.</p>
<p><strong>Searching</strong></p>
<p>For searching any key in SSTable, we need two offsets to begin with. For e.g. if we’ve to search for offset value for key10 and we’ve got offset values for key 2 and key 15, we can just use binary search to search within the SSTable since the values inside the table are sorted by key. Generally a sparse in memory index is also kept which keeps offset values for random keys to help with the binary search process.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702555613159/5197d932-66c8-49a2-bc7f-800822384b67.png" alt class="image--center mx-auto" /></p>
<p><strong>Deletion</strong></p>
<p>Deletion is worth mentioning for LSM trees as this might be the only case where deletion actually takes extra space. Since no in place updates are allowed in segment files(append only files), if a key pair is deleted, we just add a tombstone value to the key name and while merging/compaction it reads the value as tombstone and does not carry it forward in the merged segment.</p>
<h3 id="heading-lsm-tree">LSM Tree</h3>
<p>LSM tree is log structured merge tree which is essentially the algorithm we just described earlier. Searching works in the same way as above, however worst case complexity is still high in LSM tree, going through sparse index and going all the way to all on-disk SSTables. Further optimizations in LSM tree are made by introducing a bloom filter. So search is first made in bloom filter, then it goes to LSM tree.</p>
<h3 id="heading-btree">BTree</h3>
<p>BTree is a balanced tree. It possesses the properties of a n-ary binary tree with a twist that it balances itself on every insert, delete, and update.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702555653534/a16a0e7d-0c47-4f1c-ab71-035b97a4150d.png" alt class="image--center mx-auto" /></p>
<p>Each node in B-tree actually represents a page on disk. Contrast to LSM tree which divides disk into segments, B-tree splits and divides it’s data between nodes (pages) of fixed size. Insertions are slower than LSM tree but lookups are faster. B-tree also keep a WAL (Write Ahead Logs) which is an append only log file for data recovery in case of crash e.g. failure to update/add a value in the tree due to server restart or network failures. B-tree can again be reconstructed using that WAL.</p>
<h3 id="heading-b-tree">B+ Tree</h3>
<p>This is just an improved version of B tree in a sense that instead of storing references right next to the keys making the nodes heavier, it stores all the references at the leaf node. Makes range queries much faster.</p>
<h3 id="heading-other-indexes">Other indexes</h3>
<p><strong>Clustered index</strong> - Some indexes prefer keeping actual all row data in the value for key while some prefer keeping references to actual row data in the key while indexing data, the former one is known as clustered index.</p>
<p><strong>Covering index</strong> - It is a mid-way between clustered and non clustered index. It stores values for some cloumns of the row and also the reference to original row. This allows some queries to be answered just by looking at the index and for more data, we can refer to the actual values.</p>
<p><strong>Multi-column indexes</strong> - This is required for querying multiple columns of a table. E.g. if we’ve to filter out restaurants that lie within a given lat, lon values.</p>
<p>Most common multi column index is concatenated index, R-tree is also one of the multi column index.</p>
<p><strong>Column oriented storage</strong></p>
<p>→ In case of repetitive data in columns, mostly occurring due to joining tables or merging data from different sources e.g. in case of analytics data table, there is a lot of repetitive data if we just looks at the columns. Some analytics DB, store columns seperately in another table and just keep references in the main table. Further compression can be done on columns e.g. in case of number values, sparse values can be represented in a better way to save storage.</p>
]]></content:encoded></item></channel></rss>