<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Security on stdin</title><link>https://stdin.org/tags/security/</link><description>Recent content in Security on stdin</description><generator>Hugo -- 0.161.1</generator><language>en</language><copyright>Isaac Kunen</copyright><lastBuildDate>Mon, 31 Mar 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://stdin.org/tags/security/index.xml" rel="self" type="application/rss+xml"/><item><title>Lessons From the Signal Leak</title><link>https://stdin.org/lessons-from-the-signal-leak/</link><pubDate>Mon, 31 Mar 2025 00:00:00 +0000</pubDate><author>Isaac</author><guid>https://stdin.org/lessons-from-the-signal-leak/</guid><description>&amp;lt;no value&amp;gt;</description><content type="text/html" mode="escaped"><![CDATA[<p>I&rsquo;ve found a lot of the coverage about the Trump administration&rsquo;s <a href="https://www.theatlantic.com/politics/archive/2025/03/signal-group-chat-attack-plans-hegseth-goldberg/682176/">accidental leak</a> of Signal messages to The Atlantic frustrating. To read most of the coverage, the major mistake was Mike Waltz&rsquo;s inclusion of Jeffery Goldberg in the conversation, and the big questions are about the impact of this particular leak.
I have two alternative takeaways, one about the general security attitude, and one about Signal itself.</p>
<p>First the broad one.</p>
<p>Two of the things to consider when evaluating the security of a system are the capability and motivation of the assumed attacker. Most of us are worried about relatively unsophisticated adversaries that don&rsquo;t actually care that much about <em>us</em> in particular. We want to guard against the cyber-criminal out to get a credit card number, or a telco that wants to sell our info to advertisers. If we&rsquo;re harder to hack than then next guy, they&rsquo;ll just move on.</p>
<p>It&rsquo;s clearly a different case when, for example, law enforcement gets interested in <em>you</em> in specific: the adversary (&ldquo;The Law&rdquo;) is now motivated to expend significant, directed effort, and can bring in reasonably sophisticated resources, such as the FBI, to break into your device and messages.
If this is your adversary, your job is much harder, and their rate of success goes up substantially.</p>
<p>But we&rsquo;re talking about people like the Vice President, Secretary of Defense, and Director of National Security:
people who would be at the top of any US adversaries&rsquo; &ldquo;to bug&rdquo; list. The motivation is extreme. And, particularly with Russia and China, we&rsquo;re talking about highly sophisticated attackers.</p>
<p>And so it is a reasonable assumption that <em>any</em> commodity device, like those running Signal, owned by these individuals have been compromised, and that <em>every</em> conversation they have on them is being scooped up by Beijing and Moscow.
For the same reason, it&rsquo;s a reasonable assumption that their personal laptops, cars,
and homes have all been bugged.</p>
<p>This is why the government has separate systems and physical locations to hold this kind of conversation. An isolated, stripped-down, purpose-built system would be much easier to secure than even a minimal Android or iOS device.</p>
<p>We know about this particular case because Mr. Waltz accidentally included Mr. Goldberg on the conversation, leaking the whole thing to The Atlantic. But this was a minor snafu in the grand scheme of things. <em>The big mistake, made by all of the people in the group, was having the conversation on a commodity platform to begin with.</em> And while we know about this particular conversation, we don&rsquo;t know how many others these individual have broadcast to America&rsquo;s adversaries.</p>
<p>This was dumb &ndash; potentially criminally dumb &ndash; behavior by officials who should have known better, and should disqualify all of these individuals from handling classified information in the future.</p>
<p>Beyond this, I think there is a lesson to be learned from the accidental inclusion of Mr. Goldberg on this conversation, and it&rsquo;s not that Mr. Waltz is an idiot (even if he may be): it&rsquo;s about user interfaces and
Signal&rsquo;s security model.
I don&rsquo;t know whether Mr. Waltz included the <em>wrong</em> Jeffery Goldberg in the conversation, or just fat-fingered his contacts list, but either way, Signal couldn&rsquo;t have warned him that what he was doing was dumb, because Signal doesn&rsquo;t have any notion of an organization or its security boundaries: people are just people.</p>
<p>Indeed, if this group had used Slack for the conversation, or if they were jointly editing a Google Doc, the system would have almost certainly been locked down to avoid the accidental inclusion of any individual outside of the organization. Adding a person from The Atlantic would have <em>at least</em> provided a warning that this was a bad idea, and Mr. Waltz would have almost certainly not made the error.</p>
<p>I’m a fan of (and a donor to) Signal, but the lack of these organizational boundaries is a good argument against its organizational use. And I suspect that for Signal, this is just fine: that&rsquo;s not the use case they&rsquo;re targeting.</p>]]></content></item><item><title>Row-Level Security: A Cautionary Tale</title><link>https://stdin.org/row-level-security-a-cautionary-tale/</link><pubDate>Mon, 29 Jan 2018 00:00:00 +0000</pubDate><author>Isaac</author><guid>https://stdin.org/row-level-security-a-cautionary-tale/</guid><description>&amp;lt;no value&amp;gt;</description><content type="text/html" mode="escaped"><![CDATA[<p>Row-level security is a common requirement for people trying to control access to data. Some systems provide this natively, but when it&rsquo;s not provided, people often roll their own using the tools they have—with mixed results</p>
<p>In this post we&rsquo;ll explore a common way to implement row-level security on top of a relational database and see why it may not be as secure as it looks.</p>
<h2 id="a-pop-quiz">A Pop Quiz<a href="#a-pop-quiz" class="anchor" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
      stroke-linecap="round" stroke-linejoin="round" class="feather">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h2>
<p>But before we get to the crux of the issue, here&rsquo;s a quick quiz. I promise it&rsquo;s relevant.</p>
<p>What will each of the following languages do when <code>a</code> is equal to <code>0</code>​?</p>
<ol>
<li>C, C++, C#, Java, and most other C-family languages:<br>
<code>if (a != 0 &amp;&amp; 1/a &gt; 0) { /* Do something */ }</code></li>
<li>Pascal:<br>
<code>IF a &lt;&gt; 0 AND 1/a &gt; 0 THEN (* Do something *)</code></li>
<li>SQL:<br>
<code>SELECT *</code><br>
<code>FROM T</code><br>
<code>WHERE a &lt;&gt; 0 AND 1/a &gt; 0</code></li>
</ol>
<p>Obviously, I&rsquo;m asking about short circuiting behavior. I&rsquo;ll let you ponder and reveal the answers in a moment. But first, back to row-level security.</p>
<h2 id="the-setup">The Setup<a href="#the-setup" class="anchor" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
      stroke-linecap="round" stroke-linejoin="round" class="feather">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h2>
<p>Imagine that we have a table of sensitive customer information:</p>
<pre tabindex="0"><code>customers:
id  ssn        balance
--- ---------- --------
1   123456789  150.00
2   234567890  250.00
3   345678901  350.00
4   456789012  450.00
5   567890123  550.00
6   678901234  650.00
7   789012345  750.00
8   890123456  850.00
9   901234567  950.00
</code></pre><p>(Apologies if I&rsquo;ve exposed your SSN&hellip;)</p>
<p>We want to provide our employees access, but only to  <em>their</em> customers, not the entire set.</p>
<p>A common way to do this on a system that doesn&rsquo;t have built-in row-level security is to (a) add a security table that expresses which rows each user is allowed to see, (b) build a view that uses this security table to restrict the rows that each user sees, and (c) force everyone to access the data through the view.</p>
<p>So, I first create a security table that maps users to the customers they can see. E.g.,:</p>
<pre tabindex="0"><code>access:
uid    cid
------ -----
alice  1
alice  2
alice  3
isaac  4
isaac  5
isaac  6
bob    7
bob    8
bob    9
</code></pre><p>This means, e.g., that <code>isaac</code> should only be able to see customers numbered 4, 5, and 6. To enforce this we create a view:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-SQL" data-lang="SQL"><span class="line"><span class="cl"><span class="k">CREATE</span><span class="w"> </span><span class="k">VIEW</span><span class="w"> </span><span class="n">sec_customers</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">AS</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">FROM</span><span class="w"> </span><span class="n">CUSTOMERS</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">WHERE</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="k">IN</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">(</span><span class="k">SELECT</span><span class="w"> </span><span class="n">cid</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="k">access</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">uid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">USER_NAME</span><span class="p">())</span><span class="w">
</span></span></span></code></pre></div><p>I&rsquo;m showing this with SQL Server, so I&rsquo;m using the built-in function <code>USER_NAME()</code> to dynamically modify the query based on the user who accesses the view. The specifics here will vary system-to-system, but you should be able to accomplish something similar.</p>
<p>We&rsquo;ll restrict access to the base table, and let users only come in through the view. Now when <code>isaac</code> selects everything from <code>sec_customers</code>, all he sees is:</p>
<pre tabindex="0"><code>id  ssn        balance
--- ---------- --------
4   456789012  450.00
5   567890123  550.00
6   678901234  650.00
</code></pre><h2 id="the-punchline">The Punchline<a href="#the-punchline" class="anchor" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
      stroke-linecap="round" stroke-linejoin="round" class="feather">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h2>
<p>Pretty good! But before we celebrate, let&rsquo;s look at the answers to our quiz:</p>
<ol>
<li>In most C-family languages, compound predicates like this short circuit: the system will check whether <code>a != 0</code> and only execute the <code>1/a &gt; 0</code> bit if <code>a</code> isn&rsquo;t zero. The body of our conditional won&rsquo;t be executed, but life will go on as usual.</li>
<li>In Pascal there is no short circuiting: the system will  <em>always</em> execute all of the parts of the compound predicate. So if <code>a</code> is zero, the system will throw a divide-by-zero error.</li>
<li>In a particularly awesome twist of semantics, SQL short circuits <em>but doesn&rsquo;t guarantee order of operations</em>. So this code  <em>may</em> execute fine if it tests <code>a &lt;&gt; 0</code> first, or it may throw an exception if it tries the division first—you&rsquo;re at the whim of the optimizer.</li>
</ol>
<p>What does this have to do with row-level security? As I mentioned <a href="https://stdin.org/tableau-data-sources-live-vs-extract/">when discussing extract types in Tableau</a>, when you write a query against a (virtual) view in SQL, your query is composed with the view query, and this whole thing is then optimized. But SQL doesn&rsquo;t generally respect the order of the operations you&rsquo;ve written down, and this disregard runs deep. There is no &ldquo;query boundary&rdquo; when you compose queries: your operations can get shuffled around anywhere in the plan.</p>
<p>And that&rsquo;s a problem when it comes to security.</p>
<p>To illustrate, let&rsquo;s try another query against my &ldquo;secured&rdquo; customer table. I&rsquo;m going to guess the Social Security number of a customer that I shouldn&rsquo;t have access to, and see what I can find with a little SQL.</p>
<p>If I guess incorrectly, everything works as we&rsquo;d expect:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-SQL" data-lang="SQL"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">FROM</span><span class="w"> </span><span class="n">sec_customers</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">WHERE</span><span class="w"> </span><span class="mi">1</span><span class="o">/</span><span class="p">(</span><span class="n">ssn</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">789012346</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="w">
</span></span></span></code></pre></div><pre tabindex="0"><code>id  ssn        balance
--- ---------- --------
4   456789012   450.00
5   567890123   550.00
6   678901234   650.00
</code></pre><p>But if I guess correctly:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-SQL" data-lang="SQL"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">FROM</span><span class="w"> </span><span class="n">sec_customers</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">WHERE</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">7</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="mi">1</span><span class="o">/</span><span class="p">(</span><span class="n">ssn</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">789012345</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="w">
</span></span></span></code></pre></div><pre tabindex="0"><code>id  ssn        balance
--- ---------- --------
4   456789012  450.00
5   567890123  550.00
6   678901234  650.00
Msg 8134, Level 16, State 1, Line 16
Divide by zero error encountered.
</code></pre><p>And now I know that <em>a</em> customer has an SSN of 789012345: I&rsquo;ve leaked information that I shouldn&rsquo;t have leaked. And with a little work, I may be able to narrow this down to a particular customer.</p>
<p>What happened? Looking at the query plan for this query it becomes more clear:</p>
<p><img src="pushdown1.png" alt="pushdown"></p>
<p>The syntax implies that customers I don&rsquo;t have access to will be filtered out before they hit my query. But the optimizer has reordered the operations: the security filter is enforced by the join, and my predicate has been &ldquo;pushed down&rdquo; and folded into the table scan. The result is that the predicate sees the entire customer table, which results in an information-leaking exception.</p>
<h2 id="coda">Coda<a href="#coda" class="anchor" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
      stroke-linecap="round" stroke-linejoin="round" class="feather">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h2>
<p>I&rsquo;ve shown this with SQL Server, but this isn&rsquo;t a criticism of that system. Aside from the specifics around identifying the user, the mechanism I&rsquo;ve shown is likely to apply to any database with an optimizer that can rearrange operations—which is to say any database worth it&rsquo;s salt.</p>
<p>That said, while SQL Server did add first-class row-level security in SQL Server 2016, it&rsquo;s likely that it&rsquo;s using a similar mechanism under the hood. As <a href="https://docs.microsoft.com/en-us/sql/relational-databases/security/row-level-security">Microsoft&rsquo;s notes</a>:</p>
<blockquote>
<p><strong>Carefully crafted queries:</strong> It is possible to cause information leakage through the use of carefully crafted queries. For example, <code>SELECT 1/(SALARY-100000) FROM PAYROLL WHERE NAME='John Doe'</code> would let a malicious user know that John Doe&rsquo;s salary is $100,000. Even though there is a security predicate in place to prevent a malicious user from directly querying other people&rsquo;s salary, the user can determine when the query returns a divide-by-zero exception.</p>
</blockquote>
<p>Is this a worry? Well, I suppose it depends. But I&rsquo;d be reluctant to rely on this mechanism if I had a real concern about exposing data.</p>
]]></content></item></channel></rss>