<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/rss-style.xsl" type="text/xsl"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	    xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	     xmlns:dc="http://purl.org/dc/elements/1.1/"
	   xmlns:atom="http://www.w3.org/2005/Atom"
	     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	  xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>
<channel>
	<title>CyberSecurity &#8211; Terence Eden’s Blog</title>
	<atom:link href="https://shkspr.mobi/blog/tag/cybersecurity/feed/" rel="self" type="application/rss+xml" />
	<link>https://shkspr.mobi/blog</link>
	<description>Regular nonsense about tech and its effects 🙃</description>
	<lastBuildDate>Sat, 11 Apr 2026 06:53:47 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://shkspr.mobi/blog/wp-content/uploads/2023/07/cropped-avatar-32x32.jpeg</url>
	<title>CyberSecurity &#8211; Terence Eden’s Blog</title>
	<link>https://shkspr.mobi/blog</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title><![CDATA[Book Review: The Electronic Criminals by Robert Farr (1975) ★★★⯪☆]]></title>
		<link>https://shkspr.mobi/blog/2026/03/book-review-the-electronic-criminals-by-robert-farr-1975/</link>
					<comments>https://shkspr.mobi/blog/2026/03/book-review-the-electronic-criminals-by-robert-farr-1975/#respond</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sat, 07 Mar 2026 12:34:04 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[Book Review]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=68324</guid>

					<description><![CDATA[What can a fifty-year-old book teach us about cybersecurity? Written just as computing was beginning to enter the mainstream, The Electronic Criminals takes us into a terrifying new world of crime!  Fraud over Telex! Ransomware of physical tapes! Stealing passwords and hacking into mainframes!  The books has a strong start, but gently runs out of steam because there simply weren&#039;t many…]]></description>
										<content:encoded><![CDATA[<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/02/Electronic-Criminals.webp" alt="Book cover featuring a tape recorder and other electronic equipment." width="200" class="alignleft size-full wp-image-68325">

<p>What can a fifty-year-old book teach us about cybersecurity? Written just as computing was beginning to enter the mainstream, The Electronic Criminals takes us into a terrifying new world of crime!</p>

<p>Fraud over Telex! Ransomware of physical tapes! Stealing passwords and hacking into mainframes!</p>

<p>The books has a strong start, but gently runs out of steam because there simply <em>weren't</em> many electronic criminals in the mid-1970s! Instead, the book is over-stuffed with "Catch Me If You Can" tales of chequebook fraud, stolen aeroplane tickets, and regular blackmail and bribery. It isn't quite a how-to guide for the budding fraudster, but it isn't too far off.</p>

<p>Nevertheless, there are some amazing and mind-boggling computer crimes described:</p>

<blockquote><p>Computer print-outs concealed the massive fraud and fakery. Tapes were programmed so that computers would reject incriminating data and accept and produce only what would support the conspiracy. Computers were also used in playing hide-and-seek with investigators by switching data damaging to the swindlers from one code to another, just a step ahead of the authorities.</p></blockquote>

<p>One common refrain is that the law of 1975 hadn't caught up with the reality of modern crime. In the above case, the…</p>

<blockquote><p>… investors decided to sue IBM for $4 billion, claiming that the company’s inability to manufacture a swindle-proof computer had contributed to their loss. Despite the fact that IBM had claimed their computers are virtually tamper proof, the case was thrown out of court. Obviously no one can be expected to be perfect, not even an IBM computer.</p></blockquote>

<p>And in another:</p>

<blockquote><p>In a recent case in France the accused was charged with sabotage. He had intentionally erased valuable information recorded on a magnetic tape by passing it through a strong magnetic field. However, since the tape itself was undamaged the court ruled that no offense had been committed. The jury was directed to issue a verdict of “not guilty.”</p></blockquote>

<p>Many of the "electronic" crimes are able to be facilitated by poor physical processes:</p>

<blockquote><p>Computer center near London, England: Unguarded side door hooked open to allow employees to step out for fresh air. Top secret military and industrial information was stored in the center’s files.</p></blockquote>

<p>Anyone who has done an ISO 27001 audit knows that pain!</p>

<p>It isn't just computers and data-tapes that are discussed. There's rather a large section on phone-tapping and eavesdropping bugs. Rather terrifyingly, there's also a section on what we might now call "Deep Fakes":</p>

<blockquote><p>On tape recordings, words can be rearranged and new words can be built up from an assortment of syllables. The process is somewhat like fitting together bits of a jigsaw puzzle. Simply by inserting or deleting “nots” in a taped voice recording, affirmatives can be changed to negatives and negatives to affirmatives. Words can be borrowed from one part of a tape and fitted into another so the entire meaning is changed. By the same techniques, inflections of words can be altered.</p></blockquote>

<p>Oh, and drone warfare!</p>

<blockquote><p>Today there are infrared cameras that can indeed see you in the dark, even portable TV cameras that can record pictures by moonlight, and radio-controlled miniature aircraft (some that can hover like helicopters) to carry these cameras to subjects that someone wants to photograph.</p></blockquote>

<p>As with any good book on the subject, it spends plenty of time talking about how to defend oneself from these attacks and the downside of protection:</p>

<blockquote><p>Another scheme, called “hand-shaking,” requires the inquirer seeking information from the computer to correctly answer a personal question, something known only to him, before he can find out what he wants to know. This slows down the running of a business. I remember sitting in the office of a man who has a computer terminal on his desk. In the middle of our conversation a question came up and he said: “Wait a minute. I'll get the answer from our computer.” He put the question in by typing on the keyboard. The terminal’s screen lit up and displayed another question: “In what month was your mother-in-law born?”</p></blockquote>

<p>It also predicts the rise of music and film piracy; albeit by analogue means.</p>

<p>Rather pleasingly, it doesn't just limit itself to crimes committed in the USA. It acknowledges the pervasive nature of criminality and goes into some detail about cases in the UK, France, Germany, and Italy.</p>

<p>It is always fascinating to look back on our industry's history. Much like <a href="https://shkspr.mobi/blog/2022/02/book-review-information-warfare-and-security-by-dorothy-e-denning/">1999's Information Warfare and Security by Dorothy E. Denning</a>, we have to constantly go back to see what assumptions we have baked in to our processes.</p>

<p>I'll leave you with this rather chilling excerpt from the prologue:</p>

<blockquote><p>Our world is still a fine place in which to live—a better one perhaps than any previous generation has enjoyed. But some of the people in it are causing serious problems. In 1974 many people experienced diminishing respect for persons in high places who acted as if they were above the law, and this led to a loss of respect for the concept of leadership itself. We should not confuse diminishing respect for a president with respect for the presidency, for example. Our society needs people in high places. It cannot function without leadership at every level, from the head of a household to the manager of a business to a chief of state.</p>

<p>What is missing in our society today is the necessary preparation and training for the responsibilities of authority in high places. If parents in the home and people in business and government never learned the lessons of fair play when they were growing up, we cannot expect them to know how to play fair when they reach high places. Consequently we all suffer every time “the boss” makes expedient judgments rather than proper moral decisions.</p>

<p>If coming generations are to be spared the tragic consequences of even more widespread corruption, the teaching of morality in the family and in the school ought to be as important to us as curbing inflation and other socioeconomic problems. Our children should be taught how to deal with everyday actions fairly and ethically. They should be exposed to those philosophical and ethical concepts, with practical examples that illustrate the alternatives of right and wrong so that they are better able to cope.</p></blockquote>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=68324&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/03/book-review-the-electronic-criminals-by-robert-farr-1975/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Book Review: This Is How They Tell Me the World Ends - Nicole Perlroth ★⯪☆☆☆]]></title>
		<link>https://shkspr.mobi/blog/2026/02/book-review-this-is-how-they-tell-me-the-world-ends-nicole-perlroth/</link>
					<comments>https://shkspr.mobi/blog/2026/02/book-review-this-is-how-they-tell-me-the-world-ends-nicole-perlroth/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Mon, 16 Feb 2026 12:34:55 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[Book Review]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=66613</guid>

					<description><![CDATA[This cybersecurity book is badly written, contains multiple offensive stereotypes, is technically inaccurate, and spends more time focussing on the author&#039;s love affair with the New York Times than almost anything else. Seriously, if you take a drink every time the book mentions the NYT, you&#039;ll spend most of the chapters drunk. Which, to be fair, is probably the best way to experience it.  The…]]></description>
										<content:encoded><![CDATA[<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/03/9781526629838.jpg" alt="Book cover." width="270" height="415" class="alignleft size-full wp-image-66617">

<p>This cybersecurity book is badly written, contains multiple offensive stereotypes, is technically inaccurate, and spends more time focussing on the author's love affair with the New York Times than almost anything else. Seriously, if you take a drink every time the book mentions the NYT, you'll spend most of the chapters drunk. Which, to be fair, is probably the best way to experience it.</p>

<p>The epilogue pre-emptively complains that "the technical community will argue I have over-generalized and over-simplicifed". I don't have a problem with that; it is essential to write about cybersecurity for the lay audience. But this book just gets things wrong.  As a quick sample:</p>

<blockquote><p>Some pushed to have his cybersecurity license stripped.</p></blockquote>

<p>Does anyone know where I can get one of these fabled licenses?</p>

<blockquote><p>Jobert would send discs flying out of Michiel’s hard drive from two hundred yards away.</p></blockquote>

<p>If you can make a disc fly out of an HDD, something has gone <em>very</em> wrong!</p>

<p>It does become moderately interesting when the author stops gushing about the NYT and describes some of the implications behind the hacks which changed our world. The descriptions of Stuxnet, EternalBlue, and other cyberweapons are well done. But it quickly lapses back into lazy clichés.</p>

<p>For example, hackers are variously described thusly:</p>

<blockquote><p>Every bar, at every conference, was reminiscent of the Mos Eisley cantina in Star Wars. Ponytailed hackers mingled with lawyers,</p>

<p>Their diet subsisted of sandwiches and Red Bull.</p>

<p>These young men, with their sunken, glowing eyes, lived through their screens.</p>

<p>hackers—pimply thirteen-year-olds in their parents’ basements, ponytailed coders from the web’s underbelly</p>

<p>Germans don’t do small talk, and they don’t do bullshit.</p></blockquote>

<p>Then there's this:</p>

<blockquote><p>To any woman who has ever complained about the ratio of females to males in tech, I say: try going to a hacking conference. With few exceptions, most hackers I met were men who showed very little interest in anything beyond code. And jiujitsu. Hackers love jiujitsu.</p></blockquote>

<p>I don't even know where to start! Sure, the gender ratios are skewed, but every hacker I know has multiple interests and I don't think any of them include jiujitsu!</p>

<p>It's also sloppily edited. There are multiple odd typos and weird inconsistencies. For example:</p>

<blockquote><p>Leonardo famously labeled himself with the Latin phrase senza lettere—without letters—because, unlike his Renaissance counterparts, he couldn’t read Latin.</p></blockquote>

<p>He used the phrase "s<strong>a</strong>nza lettere" - not "s<strong>en</strong>za" - see <a href="http://www.mpiwg-berlin.mpg.de/sites/default/files/2021-03/Leo_Catalogo_English_final.pdf">Codex
Atlanticus</a>.</p>

<blockquote><p>not the testosterone-fueled “boo-rah” soldier Hollywood had conditioned us to.</p></blockquote>

<p>I can't find any reference to <strong>boo</strong>-rah outside of Hallowe'en articles.</p>

<blockquote><p>Panetta told an audience on the USS Intrepid in New York. “They could derail passenger trains, or even more dangerous, derail passenger trains loaded with lethal chemicals..</p></blockquote>

<p>That's <em>not</em> what he said. The author has cribbed a incorrect transcription from - of course! - the <a href="http://www.nytimes.com/2012/10/12/world/panetta-warns-of-dire-threat-of-cyberattack.html">New York Times</a>.</p>

<p>Do <em>passenger</em> trains tend to carry lethal chemicals? No, obviously not. It took me less than 5 minutes to find <a href="https://jifco.defense.gov/Media/Multimedia/IFC-Videos/videoid/158193/dvpmoduleid/128139/dvpTag/securit/">the original video</a>. At 1h 8m 22s, Panetta clearly says "derail trains loaded with". No "passenger".</p>

<blockquote><p>Littered throughout attackers’ code were references to the 1965 science fiction epic Dune, a Frank Herbert science fiction novel set in a not-too-distant future</p></blockquote>

<p>I'm not a big enough nerd to have read Dune. But <a href="https://mastodon.social/@Edent/115790559193467510">most scholars agree</a> it is set in the <em>far</em> future.</p>

<blockquote><p>A century and a half earlier, in 1949, he reminded the crowd, a dozen countries had come together to agree on basic rules of warfare.</p></blockquote>

<p>This book was written in 2020. While 1949 is a long time ago, it isn't a century ago. Perhaps this is a reference to the original 1864 convention?</p>

<p>I'll begrudgingly admit that the book does a good job of explaining some of the problems facing the world as cyber-warfare takes hold of industries and nations. But it is hidden behind so much American hegemony and basic mistakes that I found it borderline unreadable. On the rare occasions that the author stops unnecessarily inserting themself (and the New York Bloody Times) into the story, it can be rather interesting.</p>

<p>This is too important a story to be written up this badly.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=66613&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/02/book-review-this-is-how-they-tell-me-the-world-ends-nicole-perlroth/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Responsible Disclosure: Chimoney Android App and KYCaid]]></title>
		<link>https://shkspr.mobi/blog/2026/01/responsible-disclosure-chimoney-android-app-and-kycaid/</link>
					<comments>https://shkspr.mobi/blog/2026/01/responsible-disclosure-chimoney-android-app-and-kycaid/#respond</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Wed, 14 Jan 2026 12:34:52 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[Responsible Disclosure]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[WebMonetization]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=64849</guid>

					<description><![CDATA[Chimoney is a new &#34;multi-currency wallet&#34; provider. Based out of Canada, it allows users to send money to and from a variety of currencies. It also supports the new Interledger protocol for WebMonetization.  It is, as far as I can tell, unregulated by any financial institution. Nevertheless, it performs a &#34;Know Your Customer&#34; (KYC) check on all new account in order to prevent fraud.  To do this,…]]></description>
										<content:encoded><![CDATA[<p><a href="https://chimoney.app/">Chimoney</a> is a new "multi-currency wallet" provider. Based out of Canada, it allows users to send money to and from a variety of currencies. It also supports the new Interledger protocol for <a href="https://shkspr.mobi/blog/2025/08/security-flaws-in-the-webmonetization-site/">WebMonetization</a>.</p>

<p>It is, as far as I can tell, unregulated by any financial institution. Nevertheless, it performs a "Know Your Customer" (KYC) check on all new account in order to prevent fraud.  To do this, it uses the Ukranian <a href="https://kycaid.com/">KYCaid</a> platform.</p>

<p>So far, so standard. But there's a small problem with how they both integrate.</p>

<p>I installed Chimoney's Android app and attempted to go through KYCaid's verification process. For some reason it hit me with this error message.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/11/error.webp" alt="Screenshot. An error occurred and an email address." width="504" class="aligncenter size-full wp-image-64856">

<p>Well, I'd better click that email and report the problem.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/11/email-protected.webp" alt="Screenshot. The email is protected, but clickable." width="504" height="240" class="aligncenter size-full wp-image-64855">

<p>Oh, that's odd. What happens if I click the protected link?</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/11/Cloudflare.webp" alt="Screenshot. Cloudflare's email protection screen." width="504" height="625" class="aligncenter size-full wp-image-64854">

<p>Huh! I guess I've been taken to Cloudflare's website. What happens if I click on the links on their page?</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/11/discord.webp" alt="Screenshot. Invitation to join Cloudflare's Discord." width="504" height="606" class="aligncenter size-full wp-image-64853">

<p>Looks like I can now visit any site on the web. If Cloudflare has a link to it, I can go there. For example, GitHub.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/11/github.webp" alt="Screenshot. GitHub page still within the Chimoney app." width="504" height="499" class="aligncenter size-full wp-image-64852">

<h2 id="why-is-this-a-problem"><a href="https://shkspr.mobi/blog/2026/01/responsible-disclosure-chimoney-android-app-and-kycaid/#why-is-this-a-problem">Why is this a problem?</a></h2>

<blockquote><p><a href="https://mas.owasp.org/MASTG/knowledge/android/MASVS-PLATFORM/MASTG-KNOW-0018/">MASTG-KNOW-0018: WebViews</a></p>

<p>One of the most important things to do when testing WebViews is to make sure that only trusted content can be loaded in it. Any newly loaded page could be potentially malicious, try to exploit any WebView bindings or try to phish the user. <strong>Unless you're developing a browser app, usually you'd like to restrict the pages being loaded to the domain of your app.</strong> A good practice is to prevent the user from even having the chance to input any URLs inside WebViews (which is the default on Android) nor navigate outside the trusted domains. Even when navigating on trusted domains there's still the risk that the user might encounter and click on other links to untrustworthy content</p>

<p><small>Emphasis added</small></p></blockquote>

<p>A company's app is its sacred space. It shouldn't let anyone penetrate its inner sanctum because it has no control over what that 3rd party shows its customers.</p>

<p>There's nothing stopping an external service displaying a message like "To continue, please transfer 0.1 Bitcon to …"</p>

<p>(Of course, if your KYC provider - or their CDN - decides to turn evil then you probably have bigger problems!)</p>

<p>There are some other problems. It has long been known that <a href="https://discussions.apple.com/thread/7918307?sortBy=rank">people can use in-app browsers to circumvent restrictions</a>.  Some in-app browsers have <a href="https://medium.com/%40youssefhussein212103168/exploiting-insecure-android-webview-with-setallowuniversalaccessfromfileurls-c7f4f7a8db9c">insecure configurations which can be used for exploits</a>.  These sorts of "accidentally open" browsers <a href="https://matan-h.com/google-has-a-secret-browser-hidden-inside-the-settings/">are often considered to be a security vulnerability</a>.</p>

<h2 id="the-fix"><a href="https://shkspr.mobi/blog/2026/01/responsible-disclosure-chimoney-android-app-and-kycaid/#the-fix">The Fix</a></h2>

<p>Ideally, an Android app like this wouldn't use a web view. It should use a KYC provider's API rather than giving them wholesale control of the user experience.</p>

<p>But, suppose you do need a webview. What's the recommendation?</p>

<p>Boring old <a href="https://blog.oversecured.com/Android-security-checklist-webview/#insufficient-url-validation">URl validation</a> using <a href="https://developer.android.com/reference/android/webkit/WebViewClient#shouldOverrideUrlLoading(android.webkit.WebView,%20android.webkit.WebResourceRequest)">Android's <code>shouldOverrideUrlLoading()</code> method</a>.</p>

<p>Essentially, your app restricts what can be seen in the webview and rejects anything else.</p>

<h2 id="risk"><a href="https://shkspr.mobi/blog/2026/01/responsible-disclosure-chimoney-android-app-and-kycaid/#risk">Risk</a></h2>

<p>Look, this is pretty low risk. A user would have to take several deliberate steps to find themselves in a place of danger.</p>

<p>Ultimately, it is "<a href="https://wiki.c2.com/?CodeSmell">Code Smell</a>" - part of the app is giving off a noxious whiff. That's something you cannot afford to have on a money transfer app. If this simple security fix wasn't implemented, what other horrors are lurking in the source code?</p>

<h2 id="contacting-the-company"><a href="https://shkspr.mobi/blog/2026/01/responsible-disclosure-chimoney-android-app-and-kycaid/#contacting-the-company">Contacting the company</a></h2>

<p>There was no <a href="https://securitytxt.org/">security.txt</a> contact - nor anything on their website about reporting security bugs. I reached out to the CEO by email, but didn't hear back.</p>

<p>In desperation, I went on to Discord and asked in their support channel for help.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/11/send-an-email.webp" alt="Screenshot. Someone advising me on who to email." width="504" class="aligncenter size-full wp-image-64857">

<p>Unfortunately, that email address didn't exist.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/11/email-chimoney.webp" alt="Bounce message." width="504" class="aligncenter size-full wp-image-64851">

<p>I also tried contacting KYCaid, but they seemed unable or unwilling to help - and redirected me back to Chimoney.</p>

<p>As it has been over two month since I sent them video of this bug, I'm performing a responsible disclosure to make people aware of the problem.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=64849&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/01/responsible-disclosure-chimoney-android-app-and-kycaid/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Book Review: Code, Chips and Control - The Security Posture of Digital Isolation by Sal Kimmich]]></title>
		<link>https://shkspr.mobi/blog/2025/12/book-review-code-chips-and-control-the-security-posture-of-digital-isolation-by-sal-kimmich/</link>
					<comments>https://shkspr.mobi/blog/2025/12/book-review-code-chips-and-control-the-security-posture-of-digital-isolation-by-sal-kimmich/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Mon, 22 Dec 2025 12:34:29 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[Book Review]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=64250</guid>

					<description><![CDATA[My friend Sal has written a book! I was lucky enough to get early access to it.  Code, Chips and Control is an in depth look at cyber security. And I do mean in depth - this literally starts at the silicon wafer level! It isn&#039;t just about the trivial logic bugs which so often get exploited; this goes into the geopolitics of supply chains, the physics of satellite hackings, and the history of…]]></description>
										<content:encoded><![CDATA[<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/01/codechipscontrol.webp" alt="Book cover featuring circuitry." width="200" class="alignleft size-full wp-image-64252">

<p>My friend <a href="https://www.salkimmich.com/">Sal</a> has written a book! I was lucky enough to get early access to it.</p>

<p><a href="https://leanpub.com/codechipsandcontrol">Code, Chips and Control</a> is an <em>in depth</em> look at cyber security. And I do mean <strong>in depth</strong> - this literally starts at the silicon wafer level! It isn't just about the trivial logic bugs which so often get exploited; this goes into the geopolitics of supply chains, the physics of satellite hackings, and the history of the way legal systems have developed with respect to computer security.</p>

<p>It is a <em>little</em> unforgiving - there are a lot of obscure acronyms to keep in your head and it dives straight in to the problems with semiconductors. This isn't a book for casual script-kiddies.</p>

<p>That said, Sal has an evocative turn of phrase when describing complex interactions:</p>

<blockquote><p>To think about this, let’s bring out three chess boards onto a table in our minds. There is a single, invisible player - the adversary - on on side of that board. On the other side of the table there is a lot more commotion.</p>

<p>Governments huddle over one board. Security researchers cluster around another with disclosures, deadlines. Vendors and corporations share a third. The boards share the same table, the same global digital surface, their moves have always have lateral effects.</p>

<p>A public disclosure sacrificed on the researcher’s board becomes a backdoor that that advances a government’s checkmate. A patch delayed on the vendor’s board opens a flank for an adversary’s quiet advance. Disclosure is not a single match between attacker and defender. It is three simultaneous games being played out of sync.</p></blockquote>

<p>She's (rightly) scathing about some of the corporate responses that we see to the security challenges of today:</p>

<blockquote><p>In the modern enterprise, paperwork can be more lethal than malware. The result is a paradox: organizations are better at proving they responded to vulnerabilities than actually responding to them.</p></blockquote>

<p>There are a few phrases I might get stencilled onto a t-shirt:</p>

<blockquote><p>Email is not a protocol. It is a confession that the systems cannot speak [to each other].</p></blockquote>

<p>It's rather hard to summarise but this is comprehensive survey of <em>multiple</em> aspects of computer security. You get a lot of breadth and a suitable amount of depth - if you can keep up with the pace.</p>

<p><a href="https://leanpub.com/codechipsandcontrol">Code, Chips and Control</a> is available now on LeanPub.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=64250&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/12/book-review-code-chips-and-control-the-security-posture-of-digital-isolation-by-sal-kimmich/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Responsible Disclosure: Joiners, Movers, and Leavers in NHS BSA]]></title>
		<link>https://shkspr.mobi/blog/2025/12/responsible-disclosure-joiners-movers-and-leavers-in-nhs-bsa/</link>
					<comments>https://shkspr.mobi/blog/2025/12/responsible-disclosure-joiners-movers-and-leavers-in-nhs-bsa/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Tue, 02 Dec 2025 12:34:08 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[nhs]]></category>
		<category><![CDATA[Responsible Disclosure]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=64236</guid>

					<description><![CDATA[Many many years ago, I did some work for the NHS. As part of that, I was given access to certain GitHub organisations so that I could contribute to various projects. Once I left that job my access was revoked.  Mostly.  A few weeks ago, I received this email from GitHub.    On the surface, this is a sensible email. They want all their members to only have strong 2FA and I still had SMS configured …]]></description>
										<content:encoded><![CDATA[<p>Many many years ago, I did some work for the NHS. As part of that, I was given access to certain GitHub organisations so that I could contribute to various projects. Once <a href="https://shkspr.mobi/blog/2020/07/all-good-things/">I left that job</a> my access was revoked.</p>

<p>Mostly.</p>

<p>A few weeks ago, I received this email from GitHub.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/10/NHS-BSA-Github.webp" alt="Your organization, NHS Business Services Authority that you are a member of, now requires all users to only have secure two-factor authentication (2FA) methods. You currently have SMS/Text message configured as a 2FA method, which is not considered secure. To access NHS Business Services Authority resources, remove SMS/Text message as a 2FA method. " width="512" height="464" class="aligncenter size-full wp-image-64237">

<p>On the surface, this is a sensible email. They want all their members to only have strong 2FA and I still had SMS configured as a fallback method. Except, of course, I should <em>not</em> be a member. I should have been kicked out when I handed back my laptop and lanyard. There was still a bit of pandemic pandemonium about - but surely in the last few years someone should have audited the organisation's membership?</p>

<p>The <abbr title="Joiners, Movers, Leavers">JML</abbr> process is critical to cybersecurity. There's no point having fancy controls if you don't revoke the permissions of people who are no longer entitled to access.  On a fully integrated system this is (usually) easy - untick a box on Active Directory or whatever and  <em>*poof*</em> the user is banned.</p>

<p>But with <em>external</em> systems the problem is harder. You now need to keep track of external usernames, synchronise them with internal names, periodically check them for updates, integrate with an API, and - in some cases - take manual action.  It's clear that this particular bit of the NHS had slipped up. Looking through the private list of collaborators, there were <em>many</em> old accounts.</p>

<p>I was able to see all private collaborators:</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/10/view_private_members.webp" alt="Screenshot showing a redacted list of members." width="1920" height="1080" class="aligncenter size-full wp-image-64239">

<p>I could see all private repositories:</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/10/Private-Repos.webp" alt="Screenshot showing a redacted list of private repositories." width="1920" height="1080" class="aligncenter size-full wp-image-64240">

<p>I even had access to create new repositories - including special ones:</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/10/Create-New-Repo.webp" alt="Screenshot showing the ability to create new special repositories." width="1920" height="1080" class="aligncenter size-full wp-image-64241">

<p>To be abundantly clear, there was no medical data on GitHub. There was no patient data available for me to view. Absolutely nothing medically sensitive was stored there. This isn't a GDPR or medical privacy issue.  If I had made any changes to the code stored on there, it would never have made it to production. There were no API keys or sensitive data or passwords for me to exfiltrate. The <a href="https://www.nhsbsa.nhs.uk/">NHS BSA</a> is a business unit - not a medical unit.</p>

<p>Nevertheless, it is important that <em>all</em> parts of a large organisation are able to quickly and competently remove users once they have left.</p>

<h2 id="timeline"><a href="https://shkspr.mobi/blog/2025/12/responsible-disclosure-joiners-movers-and-leavers-in-nhs-bsa/#timeline">Timeline</a></h2>

<ul>
<li>2025-10-17

<ul>
<li>Received GitHub email.</li>
<li>Visited <a href="https://www.nhs.uk/.well-known/security.txt">https://www.nhs.uk/.well-known/security.txt</a> to get details of how to raise security issues.</li>
<li>Raised the issue on <a href="https://hackerone.com/edent?type=user">HackerOne</a></li>
</ul></li>
<li>2025-10-21

<ul>
<li>After triage, the issue was assigned directly to the BSA.</li>
</ul></li>
<li>2025-10-31

<ul>
<li>I was removed from the organisation.</li>
<li><img src="https://shkspr.mobi/blog/wp-content/uploads/2025/10/removed.webp" alt="You’ve been removed from the &quot;NHS Business Services Authority&quot; organization. " width="1024" height="490" class="aligncenter size-full wp-image-64238"></li>
<li>Requested permission to publish this post. No objection received.</li>
</ul></li>
<li>2025-12-02

<ul>
<li>Published</li>
</ul></li>
</ul>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=64236&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/12/responsible-disclosure-joiners-movers-and-leavers-in-nhs-bsa/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Some minor bugs in Proton's new Authenticator app]]></title>
		<link>https://shkspr.mobi/blog/2025/08/some-minor-bugs-in-protons-new-authenticator-app/</link>
					<comments>https://shkspr.mobi/blog/2025/08/some-minor-bugs-in-protons-new-authenticator-app/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sun, 31 Aug 2025 11:34:55 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[2fa]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[MFA]]></category>
		<category><![CDATA[Proton]]></category>
		<category><![CDATA[totp]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=62350</guid>

					<description><![CDATA[I maintain a a test-suite for TOTP codes. It contains a bunch of codes which adhere to the specification, some of which stretch it to breaking point, and some that are completely invalid.  These codes are a good starting point for checking whether a 2FA / MFA app works correctly.  Proton have release a swish new authenticator app for Android, iOS, Mac, Linux and Windows. Sadly, their open source…]]></description>
										<content:encoded><![CDATA[<p>I maintain a <a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/">a test-suite for TOTP codes</a>. It contains a bunch of codes which adhere to the specification, some of which stretch it to breaking point, and some that are completely invalid.  These codes are a good starting point for checking whether a 2FA / MFA app works correctly.</p>

<p>Proton have release a swish <a href="https://proton.me/authenticator">new authenticator app</a> for Android, iOS, Mac, Linux and Windows. Sadly, their <a href="https://github.com/protonpass/android-pass">open source repository</a> doesn't allow for bug reports so I'm blogging in public instead.</p>

<p>The good news is, the majority of tests pass. It accepts a wide range of acceptable codes and refuses to store most broken ones. There are a few niggles though.  None of these are severe security issues, but they probably ought to be fixed.</p>

<h2 id="very-long-codes"><a href="https://shkspr.mobi/blog/2025/08/some-minor-bugs-in-protons-new-authenticator-app/#very-long-codes">Very long codes</a></h2>

<p>The maximum number of digits which can be generated by the standard TOTP algorithm is 10.  Proton happily scans codes containing 1 - 9 digits, but complains about 10 digit codes.  So this fails:</p>

<p><code>otpauth://totp/issuer%3Aaccount%20name?secret=QWERTYUIOP&amp;digits=10&amp;issuer=issuer&amp;algorithm=SHA1&amp;period=30</code></p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/08/10digit.webp" alt="QR code for a 10 digit TOTP." width="360" height="360" class="aligncenter size-full wp-image-62370">

<p>The TOTP RFC says:</p>

<blockquote><p>Basically, the output of the HMAC-SHA-1 calculation is truncated to obtain user-friendly values</p>

<p><a href="https://datatracker.ietf.org/doc/html/rfc6238#section-1.2">1.2. Background</a></p></blockquote>

<p>But doesn't say how far to truncate.</p>

<p>There's nothing I can see in the spec that <em>prevents</em> an implementer using all 10.</p>

<p><strong>Risk:</strong> The user may not be able to store a valid code.</p>

<p><strong>Recommendation:</strong> Allow 10 digit codes.</p>

<h2 id="invalid-secrets"><a href="https://shkspr.mobi/blog/2025/08/some-minor-bugs-in-protons-new-authenticator-app/#invalid-secrets">Invalid Secrets</a></h2>

<p>Here we get to yet another <a href="https://shkspr.mobi/blog/2025/02/the-least-secure-totp-code-possible/">deficiency in the TOTP specification</a>.  How is a secret defined?</p>

<p>Google says the secret is:</p>

<blockquote><p>an arbitrary key value encoded in Base32 according to RFC 3548. The padding specified in RFC 3548 section 2.2 is not required and should be omitted.</p></blockquote>

<p>Whereas Apple says it is:</p>

<blockquote><p>An arbitrary key value encoded in Base32. Secrets should be at least 160 bits.</p></blockquote>

<p>Either way, <a href="https://www.rfc-editor.org/rfc/rfc3548#section-5">the Base32 alphabet</a> contains only uppercase letters and a few numbers.  What happens if we give it a secret like <code>QWERT!£$%^)*(YUIOP</code>?</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/08/invaid-secret.webp" alt="QR code for an invalid secret." width="360" height="360" class="aligncenter size-full wp-image-62371">

<p>Proton Authenticator just accepts it. It stores the full secret but I'm not sure how it generates the code based on it.</p>

<p><strong>Risk:</strong> The code may be generated incorrectly.</p>

<p><strong>Recommendation:</strong> Warn the user that the secret may be invalid and that a correct 2FA code cannot be guaranteed.</p>

<h2 id="issuer-mismatch"><a href="https://shkspr.mobi/blog/2025/08/some-minor-bugs-in-protons-new-authenticator-app/#issuer-mismatch">Issuer Mismatch</a></h2>

<p>In this example, the first issuer is example.com but the second issuer is microsoft.com</p>

<p><code>otpauth://totp/example.com%3Aaccount%20name?secret=QWERTYUIOP&amp;digits=6&amp;issuer=microsoft.com&amp;algorithm=SHA1&amp;period=30</code></p>

<p>What should the TOTP reader do with this? Proton chooses microsoft.com.</p>

<p>This is something which, again, is inconsistent between major providers.</p>

<p>Google says this parameter is:</p>

<blockquote><p><strong>Strongly Recommended</strong> The issuer parameter is a string value indicating the provider or service this account is associated with, URL-encoded according to RFC 3986. If the issuer parameter is absent, issuer information may be taken from the issuer prefix of the label. If both issuer parameter and issuer label prefix are present, they should be equal.</p></blockquote>

<p>Apple merely says:</p>

<blockquote><p>The domain of the site or app. The password manager uses this field to suggest credentials when setting up a new code generator.</p></blockquote>

<p>Yubico equivocates with</p>

<blockquote><p>The issuer parameter is recommended, but it can be absent. Also, the issuer parameter and issuer string in label should be equal.</p></blockquote>

<p><strong>Risk:</strong> The code may be displayed with the wrong issuer.</p>

<p><strong>Recommendation:</strong> Warn the user that there are multiple issuers. Let them choose which one is correct.</p>

<h2 id="dealing-with-defaults"><a href="https://shkspr.mobi/blog/2025/08/some-minor-bugs-in-protons-new-authenticator-app/#dealing-with-defaults">Dealing With Defaults</a></h2>

<p>What should a TOTP app do if there is missing information? Proton does the following:</p>

<ul>
<li>If the code has no number set for digits, it defaults to 6</li>
<li>If the code has no time set for period, it defaults to 30</li>
<li>If the code has no algorithm, it defaults to SHA1</li>
</ul>

<p><strong>Risk:</strong> Low. The user normally has to confirm with the issuer that the the TOTP code has been correctly stored.</p>

<p><strong>Recommendation:</strong> Let the user know that the code has missing data and may not be correct.</p>

<h2 id="odd-labels"><a href="https://shkspr.mobi/blog/2025/08/some-minor-bugs-in-protons-new-authenticator-app/#odd-labels">Odd Labels</a></h2>

<p>The label allows you to have multiple codes for the same service. For example <code>Big Bank:Personal Account</code> and <code>Big Bank:Family Savings</code>.  The Google spec is slightly confusing:</p>

<blockquote><p>The issuer prefix and account name should be separated by a literal or url-encoded colon, and optional spaces may precede the account name. Neither issuer nor account name may themselves contain a colon.</p></blockquote>

<p>What happens if there are spaces before the account name?</p>

<p><code>otpauth://totp/Spaces:%20%20%20%20%20%20%20%20%20%20%20%20test%40example.com?secret=QWERTYUIOP&amp;digits=6&amp;issuer=&amp;algorithm=SHA1&amp;period=30</code>
<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/08/spaces.webp" alt="QR code for a TOTP." width="400" height="400" class="aligncenter size-full wp-image-62374"></p>

<p>Proton strips the spaces (probably wise) but also removes the issuer.</p>

<p><strong>Risk:</strong> The user will not know which account the code is for.</p>

<p><strong>Recommendation:</strong> Keep the issuer.</p>

<h2 id="timeline"><a href="https://shkspr.mobi/blog/2025/08/some-minor-bugs-in-protons-new-authenticator-app/#timeline">Timeline</a></h2>

<p>These aren't particularly high severity bugs, nevertheless I like to give organisations a bit of time to respond.</p>

<ul>
<li>2025-07-31 - Discovered.</li>
<li>2025-08-01 - Disclosed <a href="https://bsky.app/profile/proton.me/post/3lvbnajumh22e">via a web form</a>.</li>
<li>2025-08-31 - Automatically published.</li>
</ul>

<h2 id="next-steps"><a href="https://shkspr.mobi/blog/2025/08/some-minor-bugs-in-protons-new-authenticator-app/#next-steps">Next Steps</a></h2>

<ul>
<li>If you're a user, <a href="https://codeberg.org/edent/TOTP_Test_Suite">please contribute tests</a> or give feedback.</li>
<li>If you're a developer, please check your app conforms to the specification.</li>
<li>If you're from a security company - wanna help me write up a proper RFC so this doesn't cause issues in the future?</li>
</ul>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=62350&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/08/some-minor-bugs-in-protons-new-authenticator-app/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Security Flaws in the WebMonetization Site]]></title>
		<link>https://shkspr.mobi/blog/2025/08/security-flaws-in-the-webmonetization-site/</link>
					<comments>https://shkspr.mobi/blog/2025/08/security-flaws-in-the-webmonetization-site/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Tue, 26 Aug 2025 11:34:33 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[Bug Bounty]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[Responsible Disclosure]]></category>
		<category><![CDATA[WebMonetization]]></category>
		<category><![CDATA[xss]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=62468</guid>

					<description><![CDATA[I&#039;ve written before about the nascent WebMonetization Standard. It is a proposal which allows websites to ask users for passive payments when they visit. A visitor to this site could, if this standard is widely adopted, opt to send me cash for my very fine blog posts.  All I need to do is add something like this into my site&#039;s source code:  &#60;link rel=&#34;monetization&#34;…]]></description>
										<content:encoded><![CDATA[<p>I've written before about <a href="https://shkspr.mobi/blog/2025/03/how-to-prevent-payment-pointer-fraud/">the nascent WebMonetization Standard</a>. It is a proposal which allows websites to ask users for passive payments when they visit. A visitor to this site could, if this standard is widely adopted, opt to send me cash for my very fine blog posts.</p>

<p>All I need to do is add something like this into my site's source code:</p>

<pre><code class="language-html">&lt;link rel="monetization" href="https://wallet.example.com/edent"&gt;
</code></pre>

<p>A user who has a WebMonetization plugin can then easily pay me for my content.</p>

<p>But not every website is created by an individual or a single entity. Hence, the creation of the "<a href="https://webmonetization.org/tools/prob-revshare/">Probabilistic Revenue Share Generator</a>".</p>

<blockquote><p>Probabilistic revenue sharing is a way to share a portion of a web monetized page's earnings between multiple wallet addresses. Each time a web monetized user visits the page, a recipient will be chosen at random. Payments will go to the chosen recipient until the page is closed or reloaded.</p></blockquote>

<p>Nifty! But how does it work?</p>

<p>Let's say a website is created by Alice and Bob. Alice does most of the work and is to receive 70% of the revenue. Bob is to get the remaining 30%.  Within the web page's head, the following meta element is inserted:</p>

<pre><code class="language-html">&lt;link
   rel="monetization"
   href="https://webmonetization.org/api/revshare/pay/W1siaHR0cHM6Ly9leGFtcGxlLmNvbS8iLDcwLCJBbGljZSJdLFsiaHR0cHM6Ly93aGF0ZXZlci50ZXN0LyIsMzAsIkJvYiJdXQ"
/&gt;
</code></pre>

<p>The visitor's WebMonetization plugin will visit that URl and be redirected to Alice's site 70% of time and Bob's 30%.</p>

<p>If we Base64 decode that weird looking URl, we get:</p>

<pre><code class="language-json">[
   [
      "https://example.com/",
       70,
      "Alice"
   ],
   [
      "https://whatever.test/",
       30,
      "Bob"
   ]
]
</code></pre>

<p>Rather than adding multiple URls in the head, the site points to one resource and lets that pick who receives the funds.</p>

<p>There are two small problems with this.</p>

<p>The first is that you have to trust the WebMonetization.org website. If it gets hijacked or goes rogue then all your visitors will be paying someone else. But let's assume they're secure and trustworthy. There's a slightly more insidious threat.</p>

<p>Effectively, this allows an untrusted 3rd party to use the WebMonetization.org domain as an open redirect. That's useful for phishing and other abuses.</p>

<p>For example, an attacker could send messages encouraging people to visit:</p>

<p><a href="https://webmonetization.org/api/revshare/pay/W1siaHR0cHM6Ly9leGFtcGxlLmNvbS8iLDk5LCJpbWciXV0">https://webmonetization.org/api/revshare/pay/W1siaHR0cHM6Ly9leGFtcGxlLmNvbS8iLDk5LCJpbWciXV0</a></p>

<p>Click that and you'll instantly be redirected to a domain under the attacker's control. This could be particularly bad if the domain encouraged users to share passwords or other sensitive information.</p>

<p>If the Base64 data cannot be decoded to valid JSON, the API will echo back any Base64 encoded text sent to it. This means an attacker could use it to send obfuscated messages. Consider, tor example:</p>

<p><a href="https://webmonetization.org/api/revshare/pay/W1siUGxlYXNlIHZpc2l0IFJlYWxfZ29vZF9DYXNpbm9zLmJpeiBmb3IgbG90cyBvZiBDcnlwdG8gZnVuISEhIiwxMjM0NTYsImltZyJdXQ==">https://webmonetization.org/api/revshare/pay/W1siUGxlYXNlIHZpc2l0IFJlYWxfZ29vZF9DYXNpbm9zLmJpeiBmb3IgbG90cyBvZiBDcnlwdG8gZnVuISEhIiwxMjM0NTYsImltZyJdXQ==</a></p>

<p>Visit that and you'll see a message. With a bit of effort, it could be crafted to say something to encourage a visitor to enter their credentials elsewhere.</p>

<p>When I originally reported this, the site could be used to to smuggle binary payloads. For example, <a href="https://webmonetization.org/api/revshare/pay/W1siZGF0YTppbWFnZS93ZWJwO2Jhc2U2NCxVa2xHUmtnQkFBQlhSVUpRVmxBNElEd0JBQUNRQ0FDZEFTb3dBREFBUHJWUW4weW5KQ0tpSnl0bzRCYUphUUFJSXN4NEF1OWRoRHFWQTFpMVJvUlRPN25iZHl5MDNuTTVGaHZWNjJnb1VqMzd0dXhxcGZwUGVUQlp2cko3OHcwcUFBRCsvaFZ5Rkh2WVhJck1Dam55MHo3d3FzQjkvUUUwOHhscy9BUWRYSkZYMGFkRzlsSVNzbTZrVjk2SjVGSU5CRlh6SHdmek1DcjRONnIzejUvQWEvd2ZFb1ZHWDNIOTc2c2hlM2p5UzhScUp2N0p3N2JPeG9UU1BsdTRnTmJmWFlaOVRuYmRRME1Obk1PYnlhUlFMSXU1NTZqSWowM3pmSnJWZ3FSTThHUHdSb1diMU05QWZ6RmU2TXRnMTN1RUlxclRIbWl1QnBIK2JUVkI1RUVRM3VieTBDLy9YT0FQSk9GdjRRVjhSWkRQUWQ1MTdLaHliYThKbHI5N2oya0lCSkQ5SzNtYk9IU0hpUURhc2o2WTNmb3JBVGJJZzRRWkh4V25DZXFxTWtWWWZVQWl2dUwwTC82OG1NbmFnQUFBIiw4OCwiaW1nIl1d">this URl would display an image</a> - however, it seems to have been fixed.</p>

<p>Nevertheless, it is important to recognise that the WebMonetization.org domain contains an <a href="https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html">unvalidated redirect and forwarding</a> vulnerability.</p>

<p>I recommended that they ensured that the only URls which contain legitimate payment pointers should be returned. I also suggested setting a maximum limit for URl size.</p>

<h2 id="timeline"><a href="https://shkspr.mobi/blog/2025/08/security-flaws-in-the-webmonetization-site/#timeline">Timeline</a></h2>

<ul>
<li>2025-03-27 - Discovered and disclosed.</li>
<li>2025-08-05 - Remembered I'd submitted it and sent a follow up.</li>
<li>2025-08-26 - Automatically published.</li>
<li><ins datetime="2025-08-27T15:37:49+00:00">2025-08-27</ins> - A day after this post was published, <a href="https://github.com/interledger/publisher-tools/issues/85">the issue was made public on their repo</a>.</li>
<li><ins datetime="2025-09-11T12:25:32+00:00">2025-09-10</ins> - <a href="https://github.com/interledger/publisher-tools/issues/85#issuecomment-3274623144">Confirmed fixed</a>.</li>
</ul>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=62468&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/08/security-flaws-in-the-webmonetization-site/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Are Brother's Insecure Printers Illegal in the UK?]]></title>
		<link>https://shkspr.mobi/blog/2025/07/are-brothers-insecure-printers-illegal-in-the-uk/</link>
					<comments>https://shkspr.mobi/blog/2025/07/are-brothers-insecure-printers-illegal-in-the-uk/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Tue, 01 Jul 2025 11:34:15 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[IoT]]></category>
		<category><![CDATA[law]]></category>
		<category><![CDATA[legal]]></category>
		<category><![CDATA[Legislation]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=61677</guid>

					<description><![CDATA[Another day, another security disaster! This time, multiple printers from Brother have an unfixable security flaw. That&#039;s bad, obviously, but is it illegally bad?  Let&#039;s take a look at details of the vulnerability:  An unauthenticated attacker who knows the target device&#039;s serial number, can generate the default administrator password for the device.  Recently, the UK brought in some laws aimed…]]></description>
										<content:encoded><![CDATA[<p>Another day, another security disaster! This time, <a href="https://www.theverge.com/news/694877/brother-printers-security-flaw-password-vulnerability">multiple printers from Brother have an unfixable security flaw</a>. That's bad, obviously, but is it <em>illegally</em> bad<sup id="fnref:law"><a href="https://shkspr.mobi/blog/2025/07/are-brothers-insecure-printers-illegal-in-the-uk/#fn:law" class="footnote-ref" title="I'm not a lawyer. This is not legal advice. This is just my interpretation of what's going on. If in doubt, consult someone qualified." role="doc-noteref">0</a></sup>?</p>

<p>Let's take a look <a href="https://www.cve.org/CVERecord?id=CVE-2024-51978">at details of the vulnerability</a>:</p>

<blockquote><p>An unauthenticated attacker who knows the target device's serial number, can generate the default administrator password for the device.</p></blockquote>

<p>Recently, the UK brought in some laws aimed at strengthening consumer protection - the Product Security and Telecommunications Infrastructure act (PSTI).  There's <a href="https://www.ncsc.gov.uk/blog-post/smart-devices-law">a readable summary on the National Cyber Security Centre's website</a>.</p>

<p>There are three interesting points to note in that blog post. The first is about passwords:</p>

<blockquote><p>The law means manufacturers must ensure that all their smart devices meet basic cyber security requirements. Specifically:</p>

<ol>
<li>The manufacturer must not supply devices that use default passwords, which can be easily discovered online, and shared.</li>
</ol></blockquote>

<p>Secondly, is a question of jurisdiction:</p>

<blockquote><p>Most smart devices are manufactured outside the UK, but the PSTI act also applies to all organisations importing or retailing products for the UK market. Failure to comply with the act is a criminal offence</p></blockquote>

<p>Thirdly, what is actually covered:</p>

<blockquote><p>The law applies to any ‘consumer smart device’ that connects either to the internet, or to a home network (for example by wifi).</p></blockquote>

<p>Is a WiFi enabled printer a "consumer smart device"?  One of the things that techies find confusing is that the law is <em>not</em> code. It usually doesn't enumerate a definitive list of what is and what isn't in scope. It gives a general outline and then allows case-law to develop. This means laws don't need to be updated when someone invents, say, an Internet connected tinfoil dispenser.</p>

<p>Let's move beyond the consumer-friendly summary and go to the actual law. <a href="https://www.legislation.gov.uk/uksi/2023/1007/schedule/1/made">The Product Security and Telecommunications Infrastructure (Security Requirements for Relevant Connectable Products) Regulations 2023</a></p>

<blockquote><ol start="2">
<li><p>Passwords must be—</p>

<p>a. unique per product; or</p>

<p>b. defined by the user of the product.</p></li>
<li><p>Passwords which are unique per product must not be—</p>

<p>a. based on incremental counters;</p>

<p>b. based on or derived from publicly available information;</p>

<p>c. based on or derived from unique product identifiers, such as serial numbers, unless this is done using an encryption method, or keyed hashing algorithm, that is accepted as part of good industry practice;</p>

<p>d. otherwise guessable in a manner unacceptable as part of good industry practice.</p></li>
</ol></blockquote>

<p>How does this apply to the printers? Rapid7, who discovered the vulnerability, <a href="https://www.rapid7.com/blog/post/multiple-brother-devices-multiple-vulnerabilities-fixed/">have this to say about how it works</a>:</p>

<blockquote><p>[The vulnerability] allows an attacker to leak a serial number via the target's HTTP, HTTPS, and IPP services. However, should an attacker not be able to leverage [the vulnerability], a remote unauthenticated attacker can still discover a target device's serial number via either a PJL or SNMP query</p></blockquote>

<p>So, yes. The default password <em>is</em> unique but it can be automatically derived from the serial number.  That serial number is available to anyone with a network connection to the printer.</p>

<p>But, do printers fall under the scope of this act?</p>

<p>The <a href="https://www.legislation.gov.uk/ukpga/2022/46/part/1/enacted#section-4">Product Security and Telecommunications Infrastructure Act 2022</a> says:</p>

<blockquote><p>4 Relevant connectable products</p>

<ol>
<li><p>In this Part “relevant connectable product” means a product that meets conditions A and B.</p></li>
<li><p>Condition A is that the product is—</p>

<p>A. an internet-connectable product, or</p>

<p>B. a network-connectable product.</p></li>
<li><p>Condition B is that the product is not an excepted product (see section 6).</p></li>
</ol></blockquote>

<p>It goes on to define what Internet-connectable means, along with some other clarifying details.  But is there a get-out clause here? Are printers an "excepted product"?</p>

<blockquote><p>In this Part “excepted product” means a product of a description specified in regulations made by the Secretary of State.</p></blockquote>

<p>OK, let's look at <a href="https://www.legislation.gov.uk/uksi/2023/1007/schedule/3">the regulations</a>. I've expanded out the relevant bit:</p>

<blockquote><p>Schedule 3 Excepted connectable products</p>

<ol start="5">
<li><p>Computers</p>

<ol>
<li><p>Products are excepted under this paragraph if they are computers which are—</p>

<p>a. desktop computers;</p>

<p>b. laptop computers;</p>

<p>c. tablet computers which do not have the capability to connect to cellular networks.</p></li>
</ol></li>
</ol></blockquote>

<p>Nope! The Brother printers don't appear to be exempt<sup id="fnref:neil"><a href="https://shkspr.mobi/blog/2025/07/are-brothers-insecure-printers-illegal-in-the-uk/#fn:neil" class="footnote-ref" title="With thanks to m'learned colleague Neil Brown who came to much the same conclusion" role="doc-noteref">1</a></sup>.  What's <a href="https://www.legislation.gov.uk/ukpga/2022/46/part/1/enacted#section-38">the <em>maximum</em> penalty</a> Brother could be subject to?</p>

<p>The greater of £10 million or 4% of worldwide <em>revenue</em>.</p>

<p>Ouch!</p>

<p>Of course, much like GDPR fines, these are headline grabbing numbers. The prosaic reality is that <a href="https://www.gov.uk/government/publications/safety-and-standards-enforcement-enforcement-policy">the enforcement policy is much more likely to suggest remedial steps</a>. Only the most flagrant transgressors are likely to be punished harshly<sup id="fnref:actions"><a href="https://shkspr.mobi/blog/2025/07/are-brothers-insecure-printers-illegal-in-the-uk/#fn:actions" class="footnote-ref" title="You can see the actions they've previously taken. Because PSTI is so new, there aren't any actions against insecure IoT devices - so we'll have to wait and see how they choose to proceed." role="doc-noteref">2</a></sup>.</p>

<p>So, to recap. The law says an Internet-connected device (including printers) must have a password which is not "based on or derived from publicly available information". As I understand it, having a serial-number based password is OK <em>as long as you don't publicise the serial number</em>.  I expect that if it were printed on a sticker that would be fine. But because the serial can be discovered remotely, it fails at this point.</p>

<p>In Brother's (slight) defence, unless the user has specifically connected the printer to the Internet this is only a local vulnerability. Someone on the same network would be able to monkey around with the printer but, similarly, they could plug in a USB cable for some illicit printing or break it with a hammer. Any damage is confined to the LAN.</p>

<p>Should users change default passwords? Yes. But manufacturers have a legal duty to ensure that people who don't are still protected.</p>

<div id="footnotes" role="doc-endnotes">
<hr aria-label="Footnotes">
<ol start="0">

<li id="fn:law">
<p>I'm not a lawyer. This is not legal advice. This is just my interpretation of what's going on. If in doubt, consult someone qualified.&nbsp;<a href="https://shkspr.mobi/blog/2025/07/are-brothers-insecure-printers-illegal-in-the-uk/#fnref:law" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:neil">
<p>With thanks to m'learned colleague <a href="https://decoded.legal/blog/2023/10/new-rules-for-people-making-importing-or-distributing-internet-connected-or-connectable-products-part-1/">Neil Brown who came to much the same conclusion</a>&nbsp;<a href="https://shkspr.mobi/blog/2025/07/are-brothers-insecure-printers-illegal-in-the-uk/#fnref:neil" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:actions">
<p>You can <a href="https://www.gov.uk/government/publications/opss-enforcement-actions">see the actions they've previously taken</a>. Because PSTI is so new, there aren't any actions against insecure IoT devices - so we'll have to wait and see how they choose to proceed.&nbsp;<a href="https://shkspr.mobi/blog/2025/07/are-brothers-insecure-printers-illegal-in-the-uk/#fnref:actions" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

</ol>
</div>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=61677&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/07/are-brothers-insecure-printers-illegal-in-the-uk/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Reading NFC Passport Chips in Linux]]></title>
		<link>https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/</link>
					<comments>https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Tue, 24 Jun 2025 11:34:49 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[hacking]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[nfc]]></category>
		<category><![CDATA[rfid]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=61546</guid>

					<description><![CDATA[For boring and totally not nefarious reasons, I want to read all the data contained in my passport&#039;s NFC chip using Linux. After a long and annoying search, I settled on roeften&#039;s pypassport.  I can now read all the passport information, including biometrics.  Table of ContentsBackgroundRecreating the MRZPython code to generate an MRZCan you read a cancelled passport?Cryptography and other…]]></description>
										<content:encoded><![CDATA[<p>For boring and totally not nefarious reasons, I want to read all the data contained in my passport's NFC chip using Linux. After a long and annoying search, I settled on <a href="https://github.com/roeften/pypassport">roeften's pypassport</a>.</p>

<p>I can now read all the passport information, including biometrics.</p>

<p></p><nav role="doc-toc"><menu><li><h2 id="table-of-contents"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#table-of-contents">Table of Contents</a></h2><menu><li><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#background">Background</a><menu><li><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#recreating-the-mrz">Recreating the MRZ</a><menu><li><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#python-code-to-generate-an-mrz">Python code to generate an MRZ</a></li></menu></li></menu></li><li><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#can-you-read-a-cancelled-passport">Can you read a cancelled passport?</a></li><li><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#cryptography-and-other-security">Cryptography and other security</a></li><li><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#can-you-brute-force-a-passport">Can you brute-force a passport?</a><menu><li><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#is-it-worth-brute-forcing-a-password">Is it worth brute-forcing a password?</a></li></menu></li><li><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#installing">Installing</a></li><li><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#getting-structured-data">Getting structured data</a><menu><li><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#saving-the-image">Saving the image</a></li></menu></li><li><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#what-didnt-work">What didn't work</a><menu><li><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#mrtdreader">mrtdreader</a></li><li><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#jean-francois-houzards-and-olivier-rogers-pypassport">Jean-Francois Houzard's and Olivier Roger's pyPassport</a></li><li><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#beaujeans-pypassport">beaujean's pyPassport</a></li><li><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#d-logic">d-Logic</a></li><li><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#android-reader">Android reader</a></li></menu></li><li><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#is-it-worth-it">Is it worth it?</a></li></menu></li></menu></nav><p></p>

<h2 id="background"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#background">Background</a></h2>

<p>The NFC chip in a passport is protected by a password. The password is printed on the inside of the physical passport. As well as needing to be physically close to the passport for NFC to work<sup id="fnref:long"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#fn:long" class="footnote-ref" title="There are some commercially available long range readers - up to 15cm! I've no doubt some clever engineer has made a some high-powered radio device which can read things from a mile away using a…" role="doc-noteref">0</a></sup>, you also need to be able to see the password. The password is printed in the "Machine Readable Zone" (MRZ) - which is why some border guards will swipe your passport through a reader before scanning the chip; they need the password and don't want to type it in.</p>

<p>I had a small problem though.  I'm using my old passport<sup id="fnref:old"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#fn:old" class="footnote-ref" title="I'm not dumb enough to do this stuff on a live passport!" role="doc-noteref">1</a></sup> which <a href="https://www.gov.uk/government/publications/cancellation-of-passports/cancelling-british-passports-accessible#cancelling-epassport-version-2">has been cancelled</a>.  Cancelling isn't just about revoking the document. It is also physically altered:</p>

<blockquote><p>Cut off the bottom left hand corner of the personal details page, making sure you cut the MRZ on the corner opposite the photo.</p></blockquote>

<p>So a chunk of the MRZ is missing! Oh no! Whatever can we do!?</p>

<h3 id="recreating-the-mrz"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#recreating-the-mrz">Recreating the MRZ</a></h3>

<p>The password is made up of three pieces of data:</p>

<ol>
<li>Passport Number (Letters and Numbers)</li>
<li>Date of Birth (YYMMDD)</li>
<li>Expiry Date (YYMMDD)</li>
</ol>

<p>Each piece <em>also</em> has a checksum. This calculation is defined in Appendix A to <a href="https://www.icao.int/publications/Documents/9303_p3_cons_en.pdf">Part 3 of Document 9303</a>.</p>

<p>Oh, and there's a checksum for the entire string. It's this final checksum which is cut off when the passport cover is snipped.</p>

<p>The final password is: <code>Number Number-checksum DOB DOB-checksum Expiry Expiry-checkum checksum-of-previous-digits</code></p>

<h4 id="python-code-to-generate-an-mrz"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#python-code-to-generate-an-mrz">Python code to generate an MRZ</a></h4>

<p>If you know the passport number, date of birth, and expiry date, you can generate your own Machine Readable Zone - this acts as the password for the NFC chip.</p>

<pre><code class="language-python">def calculateChecksum( value ):
    weighting = [7,3,1]
    characterWeight = {
        '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7,  
        '8': 8, '9': 9, '&lt;': 0, 'A':10, 'B':11, 'C':12, 'D':13, 'E':14, 
        'F':15, 'G':16, 'H':17, 'I':18, 'J':19, 'K':20, 'L':21, 'M':22, 
        'N':23, 'O':24, 'P':25, 'Q':26, 'R':27, 'S':28, 'T':29, 'U':30, 
        'V':31, 'W':32, 'X':33, 'Y':34, 'Z':35
    }
    counter = 0
    result = 0
    for x in value:
        result += characterWeight[str(x)] * weighting[counter%3]
        counter += 1
    return str(result%10)

def calculateMRZ( passportNumber, DOB, expiry ):
    """
    DOB and expiry are formatted as YYMMDD
    """
    passportCheck = calculateChecksum( passportNumber )
    DOBCheck      = calculateChecksum( DOB )
    expiryCheck   = calculateChecksum( expiry )
    mrzNumber  = passportNumber + passportCheck + DOB + DOBCheck + expiry + expiryCheck
    mrzCheck = calculateChecksum( mrzNumber ).zfill(2)
    mrz =  passportNumber + passportCheck + "XXX" + DOB + DOBCheck + "X" + expiry + expiryCheck + "&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;" + mrzCheck
    return mrz

print( calculateMRZ("123456789", "841213", "220229") )
</code></pre>

<h2 id="can-you-read-a-cancelled-passport"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#can-you-read-a-cancelled-passport">Can you read a cancelled passport?</a></h2>

<p>I would have thought that cutting the cover of the passport would destroy the antenna inside it. But, going back to <a href="https://www.gov.uk/government/publications/cancellation-of-passports/cancelling-british-passports-accessible#cancelling-epassport-version-2">the UK guidance</a>:</p>

<blockquote><p>You must not cut the back cover on the ePassport</p></blockquote>

<p>Ah! That's where the NFC chip is. I presume this is so that cancelled passports can still be verified for authenticity.</p>

<h2 id="cryptography-and-other-security"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#cryptography-and-other-security">Cryptography and other security</a></h2>

<p>The security is, thankfully, all fairly standard Public Key Cryptography - <a href="https://www.icao.int/publications/Documents/9303_p11_cons_en.pdf">9303 part 11</a> explains it in <em>excruciating</em> levels of detail.</p>

<p>One thing I found curious - because the chip has no timer, it cannot know how often it is being read. You could bombard it with thousands of password attempts and not get locked out.  Indeed, the specification says:</p>

<blockquote><p>the success probability of the attacker is given by the time the attacker has access to the IC, the duration of a single attempt to guess the password, and the entropy of the passport.</p></blockquote>

<h2 id="can-you-brute-force-a-passport"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#can-you-brute-force-a-passport">Can you brute-force a passport?</a></h2>

<p>Wellllll… maybeeeee…?</p>

<p>Passports are generally valid for only 10 years. So that's 36,525 possible expiry dates.</p>

<p>Passport holders are generally under 100 years old. So that's 3,652,500 possible dates of birth.</p>

<p>That's already 133,407,562,500 attempts - and we haven't even got on to the 1E24 possible passport numbers!</p>

<p>In my experiments, sending an incorrect but valid MRZ results in the chip returning "Security status not satisfied (0x6982)" in a very short space of time. Usually less than a second.</p>

<p>But sending that incorrect attempt seemed to introduce a delay in the next response - by a few seconds. Sending the correct MRZ seemed to reset this and let the chip be read instantly.</p>

<p>So, if you knew the target's passport number and birthday, brute forcing the expiry date would take a couple of days. Not instant, but not impossible.</p>

<p>Most <a href="https://www.nxp.com/docs/en/data-sheet/NTAG213_215_216.pdf">commercial NFC chips support 100,000 writes</a> with no limit for the number of reads. Some also have a 24 bit read counter which increments after every read attempt. After 16 million reads, the counter doesn't increment. It <em>could</em> be possible for a chip to self-destruct after a specific number of reads - but I've no evidence that passport chips do that.</p>

<h3 id="is-it-worth-brute-forcing-a-password"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#is-it-worth-brute-forcing-a-password">Is it <em>worth</em> brute-forcing a password?</a></h3>

<p>If you were to brute-force the MRZ, you would discover the passport-holder's date of birth.  You would also get:</p>

<ul>
<li>A digital copy of their photo,</li>
<li>Their full name,</li>
<li>Their sex<sup id="fnref:sex"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#fn:sex" class="footnote-ref" title="Sex is complicated. But ICAO allow for &quot;F for female, M for male, or X for unspecified&quot;." role="doc-noteref">2</a></sup>,</li>
<li>The country which issued their passport, and</li>
<li>Their nationality.</li>
</ul>

<p>All of that is something which you can see from looking at the passport. So there's little value in attempting to read it electronically.</p>

<h2 id="installing"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#installing">Installing</a></h2>

<p>As mentioned, I'm using <a href="https://github.com/roeften/pypassport">https://github.com/roeften/pypassport</a></p>

<p>The only library I needed to install was <a href="https://pypi.org/project/pyasn1/">pyasn1</a> using <code>pip3 install pyasn1</code> - your setup may vary.</p>

<p>Download PyPassport. In the same directory, you can create a test Python file to see if the passport can be read. Here's what it needs to contain:</p>

<pre><code class="language-python">from pypassport import epassport, reader

#   Replace this MRZ with the one from your passport
MRZ = "1234567897XXX8412139X2202299&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;04"

def trace(name, msg):
    if name == "EPassport":
        print(name + ": " + msg)

r = reader.ReaderManager().waitForCard()

ep = epassport.EPassport(r, MRZ)
ep.register(trace)
ep.readPassport()
</code></pre>

<p>Plug in your NFC reader, place your passport on it, run the above code.  If it works, it will spit out a lot of debug information, including all the data it can find on the passport.</p>

<h2 id="getting-structured-data"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#getting-structured-data">Getting structured data</a></h2>

<p>The structure of the passport data is a little convoluted.  <a href="https://www.icao.int/publications/Documents/9303_p10_cons_en.pdf">The specification</a> puts data into different "Data Groups" - each with its own ID.</p>

<p>By running:</p>

<pre><code class="language-python">ep.keys()
</code></pre>

<p>You can see which Data Groups are available. In my case, <code>['60', '61', '75', '77']</code></p>

<ul>
<li><code>60</code> is the common area which contains some metadata. Nothing interesting there.</li>
<li><code>61</code> is DG1 - the full MRZ. This contains the holder's name, sex, nationality, etc.</li>
<li><code>77</code> is the Document Security Object - this was empty for me.</li>
<li><code>75</code> is DG2 to DG4 Biometric Templates - this contains the image and other metadata.</li>
</ul>

<p>Dumping the biometrics - <code>print( ep["75"] )</code> - gives these interesting pieces of metadata:</p>

<pre><code class="language-_">'83': '20190311201345',
'meta': {   'Expression': 'Unspecified',
            'EyeColour' : 'Unspecified',
            'FaceImageBlockLength': 19286,
            'FaceImageType': 'Basic',
            'FeatureMask': '000000',
            'FeaturePoint': {0: {'FeaturePointCode': 'C1',
                                'FeatureType': '01',
                                'HorizontalPosition': 249,
                                'Reserved': '0000',
                                'VerticalPosition': 216},
                            1: {'FeaturePointCode': 'C2',
                                'FeatureType': '01',
                                'HorizontalPosition': 141,
                                'Reserved': '0000',
                                'VerticalPosition': 214}},
            'Features': {},
            'Gender': 'Unspecified',
            'HairColour': 'Unspecified',
            'ImageColourSpace': 'RGB24',
            'ImageDataType': 'JPEG',
            'ImageDeviceType': 0,
            'ImageHeight': 481,
            'ImageQuality': 'Unspecified',
            'ImageSourceType': 'Static Scan',
            'ImageWidth': 385,
            'LengthOfRecord': 19300,
            'NumberOfFacialImages': 1,
            'NumberOfFeaturePoint': 2,
            'PoseAngle': '0600B5',
            'PoseAngleUncertainty': '000000',
            'VersionNumber': b'010'
        }
</code></pre>

<p>If I understand <a href="https://www.icao.int/security/mrtd/siteassets/pages/technical-reports/tr%20-%20rf%20and%20protocol%20testing%20part%204%20v2.10.pdf">the testing document</a> - the "Feature Points" are the middle of the eyes.  Interesting to see that gender (not sex!) and hair colour are also able to be recorded. The "PoseAngle" represents the <a href="https://www.icao.int/Security/FAL/TRIP/Documents/TR%20-%20Portrait%20Quality%20v1.0.pdf">pitch, yaw, and roll</a> of the face.</p>

<h3 id="saving-the-image"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#saving-the-image">Saving the image</a></h3>

<p>Passport images are saved either with JPEG or with <a href="https://www.icao.int/Security/FAL/TRIP/Documents/TR%20-%20Portrait%20Quality%20v1.0.pdf">JPEG2000 encoding</a>. Given the extremely limited memory available photos are small and highly compressed. Mine was a mere 19KB.</p>

<p>To save the image, grab the bytes and plonk them onto disk:</p>

<pre><code class="language-python">photo = ep["75"]["A1"]["5F2E"]
with open( "photo.jpg", "wb" ) as f:
   f.write( photo )
</code></pre>

<p>As expected, the "FeaturePoints" co-ordinates corresponded roughly to the centre of my eyes. Nifty!</p>

<h2 id="what-didnt-work"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#what-didnt-work">What didn't work</a></h2>

<p>I tried a few different tools. Listed here so you don't make the same mistakes as me!</p>

<h3 id="mrtdreader"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#mrtdreader">mrtdreader</a></h3>

<p>The venerable <a href="https://github.com/rubund/mrtdreader">mrtdreader</a>. My NFC device beeped, then mrtdreader said "No NFC device found."</p>

<p>I think this is because <a href="https://github.com/nfc-tools/libnfc/issues/719">NFC Tools haven't been updated in ages</a>.</p>

<h3 id="jean-francois-houzards-and-olivier-rogers-pypassport"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#jean-francois-houzards-and-olivier-rogers-pypassport">Jean-Francois Houzard's and Olivier Roger's pyPassport</a></h3>

<p>I looked at <a href="https://code.google.com/archive/p/pypassport/">pyPassport</a> but it is only available for Python 2.</p>

<h3 id="beaujeans-pypassport"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#beaujeans-pypassport">beaujean's pyPassport</a></h3>

<p>This <a href="https://github.com/beaujeant/pypassport">pypassport</a> only checks if a passport is resistant to specific security vulnerabilities.</p>

<h3 id="d-logic"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#d-logic">d-Logic</a></h3>

<p><a href="https://www.d-logic.com/nfc-rfid-reader-sdk/software/epassport-reading/">Digital Logic's ePassport software</a> only works with their hardware readers.</p>

<h3 id="android-reader"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#android-reader">Android reader</a></h3>

<p><a href="https://github.com/tananaev/passport-reader">tananaev's passport-reader</a> - works perfectly on Android. So I knew my passport chip was readable - but the app won't run on Linux.</p>

<h2 id="is-it-worth-it"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#is-it-worth-it">Is it worth it?</a></h2>

<p>Yeah, I reckon so! Realistically, you aren't going to be able to crack the MRZ to read someone's passport. But if you need to gather personal information<sup id="fnref:gdpr"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#fn:gdpr" class="footnote-ref" title="Under the auspices of GDPR, of course!" role="doc-noteref">3</a></sup>, it's perfectly possible to do so quickly from a passport.</p>

<p>The MRZ is a <em>Machine Readable</em> Zone - so it is fairly simple to OCR the text and then pass that to your NFC reader.</p>

<p>And even if the MRZ is gone, you can reconstruct it from the data printed on the passport.</p>

<p>Of course, this won't be able to detect fraudulent passports. It doesn't check against a database to see if it has been revoked<sup id="fnref:interpol"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#fn:interpol" class="footnote-ref" title="Nor does it check if the holder is on some Interpol list." role="doc-noteref">4</a></sup>. I don't think it will detect any cryptographic anomalies.</p>

<p>But if you just want to see what's on your travel documents, it works perfectly.</p>

<div id="footnotes" role="doc-endnotes">
<hr aria-label="Footnotes">
<ol start="0">

<li id="fn:long">
<p>There are some <a href="https://www.shopnfc.com/en/nfc-readers-writers/300-nfc-xl-reader-long-range-hf-reader.html">commercially available long range readers</a> - up to 15cm! I've no doubt some clever engineer has made a some high-powered radio device which can read things from a mile away using a <a href="https://www.makeuseof.com/tag/how-to-make-a-wifi-antenna-out-of-a-pringles-can-nb/">Pringle's tube</a>. Of note, the <a href="https://www.icao.int/publications/Documents/9303_p11_cons_en.pdf">ICAO guidance</a> says:</p>

<blockquote><p>the unencrypted communication between a contactless IC and a reader can be eavesdropped within a distance of several metres.</p></blockquote>

<p><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#fnref:long" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:old">
<p>I'm not dumb enough to do this stuff on a <em>live</em> passport!&nbsp;<a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#fnref:old" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:sex">
<p>Sex is complicated<sup id="fnref:giggle"><a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#fn:giggle" class="footnote-ref" title="Stop giggling at the back!" role="doc-noteref">5</a></sup>. But ICAO allow for "<a href="https://www.icao.int/publications/Documents/9303_p4_cons_en.pdf">F for female, M for male, or X for unspecified</a>".&nbsp;<a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#fnref:sex" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:gdpr">
<p>Under the auspices of GDPR, of course!&nbsp;<a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#fnref:gdpr" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:interpol">
<p>Nor does it check if the holder is on some Interpol list.&nbsp;<a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#fnref:interpol" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:giggle">
<p>Stop giggling at the back!&nbsp;<a href="https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/#fnref:giggle" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

</ol>
</div>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=61546&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-in-linux/feed/</wfw:commentRss>
			<slash:comments>9</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Your Password Algorithm Sucks]]></title>
		<link>https://shkspr.mobi/blog/2025/06/your-password-algorithm-sucks/</link>
					<comments>https://shkspr.mobi/blog/2025/06/your-password-algorithm-sucks/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Mon, 16 Jun 2025 11:34:07 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[passwords]]></category>
		<category><![CDATA[security]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=61259</guid>

					<description><![CDATA[There are two sorts of people in the world; those who know they are stupid and those who think they are clever.  Stupid people use a password manager. They know they can&#039;t remember a hundred different passwords and so outsource the thinking to something reasonably secure. I&#039;m a stupid person and am very happy to have BitWarden generate and save fiendishly complex unique passwords which are then…]]></description>
										<content:encoded><![CDATA[<p>There are two sorts of people in the world; those who know they are stupid and those who think they are clever.</p>

<p>Stupid people use a password manager. They know they can't remember a hundred different passwords and so outsource the thinking to something reasonably secure. I'm a stupid person and am very happy to have BitWarden generate and save fiendishly complex unique passwords which are then protected by the app's MFA. Lovely!</p>

<p>But people who think they are clever decide to bypass that and use their own super-secret algorithm.</p>

<p>Every clever person's algorithm boils down to the same thing:</p>

<ol>
<li>Have a single strong main password.</li>
<li>Add to it some information related to the service.</li>
</ol>

<p>For example <code>P@ssw0rd!_facebook</code> and <code>P@ssw0rd!_linkedin</code>. On the surface, that's quite an attractive proposition. You remember one thing and you don't need to trust a password manager.</p>

<p>People who are <em>extra</em> clever use the same algorithm but wrap it in a command-line function which XORs both pieces of data, creates a SHA-512 hash, takes every prime numbered bit, converts to ASCII, and uses <em>that</em> to generate a password. <a href="https://www.youtube.com/watch?v=ls5BFzuxGw4">Smart!</a></p>

<p>Either way, these algorithms <strong>suck!</strong>  Let me explain why.</p>

<h2 id="password-leaking"><a href="https://shkspr.mobi/blog/2025/06/your-password-algorithm-sucks/#password-leaking">Password Leaking</a></h2>

<p>One day, LinkedIn decides to <a href="https://www.linkedin.com/blog/member/trust-and-safety/protecting-our-members">LeakedOut its users' passwords</a>. Anyone who can see <code>P@ssw0rd!_linkedin</code> can make a pretty good guess at your password for Facebook, banking, dating, and shopping etc.  This means you now need to change <em>every</em> password that you have.</p>

<p>Even if you have used some amazing cryptographic powerhouse of an algorithm, there's still a chance you'll accidentally leak it or get so paranoid that you decide to invalidate it. Now you need to change your password on hundreds of sites.</p>

<h2 id="password-rotation"><a href="https://shkspr.mobi/blog/2025/06/your-password-algorithm-sucks/#password-rotation">Password Rotation</a></h2>

<p>We all know that it is <a href="https://www.ncsc.gov.uk/collection/passwords/updating-your-approach">a bad idea to ask your users to regularly change their passwords</a> - yet sites often persist in doing so.</p>

<p>How does your algorithm cope with this?</p>

<p>Do you have to remember that it is <code>P@ssw0rd!_facebook_1</code> and <code>P@ssw0rd!_linkedin_23</code>?</p>

<p>Perhaps you'll write down all the suffixes and find a way to store them securely - like, say, a password manager?</p>

<h2 id="password-requirements"><a href="https://shkspr.mobi/blog/2025/06/your-password-algorithm-sucks/#password-requirements">Password Requirements</a></h2>

<p>One site says "Your password <em>must</em> contain a special character and a number" another says "You can use any special character <em>except</em> % or ?" another refuses to let your password contain two consecutive identical characters, or it <em>must</em> start with a number, or it cannot be longer than 12 characters. Yes, I know password rules like this aren't sensible - but they <em>are</em> common.</p>

<p>How does your algorithm cope with that?</p>

<p>If you manually have to tweak a couple of dozen passwords generated by your algorithm, you are going to tie yourself in knots remembering the arcane requirements for each one.</p>

<h2 id="be-stupid-use-a-password-manager"><a href="https://shkspr.mobi/blog/2025/06/your-password-algorithm-sucks/#be-stupid-use-a-password-manager">Be Stupid - Use A Password Manager</a></h2>

<p>Humans are stupid<sup id="fnref:not"><a href="https://shkspr.mobi/blog/2025/06/your-password-algorithm-sucks/#fn:not" class="footnote-ref" title="Not you, of course. You're mummy's extra-special boy who never makes mistakes." role="doc-noteref">0</a></sup>. Humans get tired, forgetful, or sick. Our delicious meaty brains are not optimised to remember long strings of complex information or hundreds of rarely used combinations. Knowing that you know not is a super-power. It allows you to offload things that you don't understand to something more competent.</p>

<p>Pick a password manager. Secure it with a reasonably strong password and multi-factor authentication. Let it do the hard work of remembering.</p>

<div id="footnotes" role="doc-endnotes">
<hr aria-label="Footnotes">
<ol start="0">

<li id="fn:not">
<p>Not you, of course. You're mummy's extra-special boy who never makes mistakes.&nbsp;<a href="https://shkspr.mobi/blog/2025/06/your-password-algorithm-sucks/#fnref:not" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

</ol>
</div>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=61259&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/06/your-password-algorithm-sucks/feed/</wfw:commentRss>
			<slash:comments>18</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[What is a "Cyber Attack"?]]></title>
		<link>https://shkspr.mobi/blog/2025/06/what-is-a-cyber-attack/</link>
					<comments>https://shkspr.mobi/blog/2025/06/what-is-a-cyber-attack/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Thu, 05 Jun 2025 11:34:57 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[security]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=61135</guid>

					<description><![CDATA[Terminology is hard. Computer terminology is even harder. Humans are animals who just love to classify things. We have a fundamental need in our delicious meaty brains to put things into conceptual buckets.  This, I think, leads to some unfortunate consequences when our categories don&#039;t match up with other people&#039;s categories.  For example, take this news story and this journalist&#039;s response to…]]></description>
										<content:encoded><![CDATA[<p>Terminology is hard. <em>Computer</em> terminology is even harder. Humans are animals who just <em>love</em> to classify things. We have a fundamental need in our delicious meaty brains to put things into conceptual buckets.  This, I think, leads to some unfortunate consequences when our categories don't match up with other people's categories.</p>

<p>For example, take this news story and this journalist's response to it:</p>

<blockquote class="bluesky-embed" data-bluesky-uri="at://did:plc:4uyo4p7dnrovo2q2d4tya2vf/app.bsky.feed.post/3lqtp77uwyk2p" data-bluesky-cid="bafyreihxb766fu5it5ilrsjckvnpkakf5fcmw4kvvxbooiyb5vrzus47ay"><p lang="en">100,000 taxpayers will be told shortly that their @HMRCgovuk accounts have been hacked and £47m stolen by thieves claiming fake tax repayments bit.ly/4mSDrMs extraordinary admission to MPs from top official who claims it wasn’t a cyberattack!</p>— <a href="https://bsky.app/profile/did:plc:4uyo4p7dnrovo2q2d4tya2vf?ref_src=embed">Paul Lewis (@paullewismoney.bsky.social)</a> <a href="https://bsky.app/profile/did:plc:4uyo4p7dnrovo2q2d4tya2vf/post/3lqtp77uwyk2p?ref_src=embed">2025-06-05T06:33:24.098Z</a></blockquote>

<script async="" src="https://embed.bsky.app/static/embed.js" charset="utf-8"></script>

<p>I think it is pretty reasonable to say that having 100,000 accounts breached using a computer <em>is</em> a "cyberattack". So how do the UK tax authorities square that circle?  Angela MacDonald, the deputy chief executive of HMRC, said:</p>

<blockquote><p>MacDonald stressed that the breach was “not a cyberattack, we have not been hacked, we have not had data extracted from us”.</p>

<p>She later said: “The ability for somebody to breach your systems and to extract data, to hold you to ransomware and all of those things, that is a cyberattack. That is not what has happened here.”</p>

<p>…</p>

<p>“This was not a cyberattack — it involved criminals using personal information from phishing activity or data obtained elsewhere to try to claim money from HMRC. We’re writing to those customers affected to reassure them we’ve secured their accounts and that they haven’t lost any money.”</p>

<p><a href="https://www.thetimes.com/article/24aef47e-978e-400d-bf6c-b6932e737cbc?shareToken=9d7a9b9250df0ea4ba9b3426d24492f9">Criminals access 100,000 people’s tax records</a></p></blockquote>

<p>Ah. I think that's pretty reasonable. Well, up to a point.</p>

<p>If you set your HMRC password to be "password" and someone guesses that - it is <em>you</em> who has been attacked; not the online service.</p>

<p>Here's what has probably happened in this case.</p>

<ul>
<li>You signed up to an online service.</li>
<li>You used your regular email and password.</li>
<li>The service <a href="https://haveibeenpwned.com/Breach/LinkedIn">got hacked and leaks everyone's details</a>.</li>
<li>A criminal went <a href="https://owasp.org/www-community/attacks/Credential_stuffing">credential stuffing</a> and tried all the usernames and password on lots of sites.</li>
<li>One of those sites was HMRC and the criminal started filling their pockets.</li>
</ul>

<p>Who is being "cyberattacked" here?  HMRC say that no individual lost any money - although I suspect people will possibly feel various administrative repercussions. It is hard to feel that the individual is the victim.</p>

<p>HMRC didn't have any malware or ransomware installed. None of their computers were misused. Vast globs of data were not exfiltrated.</p>

<p>But were HMRC's digital defences breached? <em>Maybe…</em></p>

<p>Let's suppose that the cybercriminal who did this was an idiot. Here's what they <em>might</em> have done:</p>

<ul>
<li>Used a single IP address</li>
<li>From a "dangerous" country</li>
<li>Trying 1,000 passwords per second</li>
</ul>

<p>At which point, HMRC's systems should have started flashing red, sirens wailing, and countermeasures deployed. Any one or combination of the above should have been enough to trigger a "something fishy is going on here" alert. I think that scenario would be fair to describe it as <em>looking like</em> a cyberattack - although, depending on their risk tolerance it might be described as "<a href="https://knowyourmeme.com/memes/anatoly-dyatlov">not great, not terrible</a>".</p>

<p>But if the attacker was smart, they'd have rotated through thousands of UK-based IP addresses and kept their stuffing volume below the noise threshold.  Whereupon their attempts would likely have gone unnoticed.</p>

<p>Is a small and subtle attack still an attack? Yes.</p>

<h2 id="was-this-a-cyberattack"><a href="https://shkspr.mobi/blog/2025/06/what-is-a-cyber-attack/#was-this-a-cyberattack">Was this a cyberattack?</a></h2>

<p>I don't think it matters. Sorting things into predefined buckets is often just a way to bypass responsibility and accountability. Concentrating on the name of the thing rather than the thing itself doesn't help victims and doesn't prevent the incident from happening again.</p>

<p>Every counter-measure which HMRC could deploy will negatively affect legitimate users. Getting bombarded with emails saying "did you just try to log in?" is an annoyance, mandating 2FA excludes less technical users, banning suspicious IP addresses inevitably leads to false positives, rate-limits hit legitimate users. And, ultimately, (whisper it) users bear <em>some</em> of the blame for their poor password practices.</p>

<p>I'm sure HMRC will tighten up their monitoring, I'm sure some individuals will have better password hygiene, and I'm sure criminals will find a way to bypass both.</p>

<p>As ontology is difficult, I'll leave you with this instructional video.</p>

<iframe title="What Makes Soup, Soup? | Short Stuff | Comedy" width="620" height="349" src="https://www.youtube.com/embed/Y1HVTNxwt7w?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=61135&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/06/what-is-a-cyber-attack/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[That's Not How A SIM Swap Attack Works]]></title>
		<link>https://shkspr.mobi/blog/2025/04/thats-not-how-a-sim-swap-attack-works/</link>
					<comments>https://shkspr.mobi/blog/2025/04/thats-not-how-a-sim-swap-attack-works/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Thu, 17 Apr 2025 11:34:54 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[2fa]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[MFA]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[sim]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=59603</guid>

					<description><![CDATA[There&#039;s a disturbing article in The Guardian about a person who was on the receiving end of a successful cybersecurity attack.  EE texted to say they had processed my sim activation request, and the new sim would be active in 24 hours. I was told to contact them if I hadn’t requested this. I hadn’t, so I did so immediately. Twenty-four hours later, my mobile stopped working and money was wit…]]></description>
										<content:encoded><![CDATA[<p>There's <a href="https://www.theguardian.com/money/2025/apr/15/ee-was-unapologetic-after-i-tried-to-stop-a-sim-swap">a disturbing article in The Guardian</a> about a person who was on the receiving end of a successful cybersecurity attack.</p>

<blockquote><p>EE texted to say they had processed my sim activation request, and the new sim would be active in 24 hours. I was told to contact them if I hadn’t requested this. I hadn’t, so I did so immediately. Twenty-four hours later, my mobile stopped working and money was withdrawn from my bank account.
</p><p><strong>With their alien sim, the ­fraudster infiltrated my handset and stole details for every account I had.</strong> Passwords and logins had been changed for my finance, retail and some social media accounts. </p></blockquote>

<p>(Emphasis added.)</p>

<p>I realise it is in the consumer rights section of the newspaper, not the technology section, and I dare-say some editorialising has gone on, but that's <em>nonsense</em>.</p>

<p>Here's how a SIM swap works.</p>

<ol>
<li>Attacker convinces your phone company to reassign your telephone number to a new SIM.</li>
<li>Attacker goes to a website where you have an account, and initiates a password reset.</li>
<li>Website sends a verification code to your phone number, which is now in the hands of the attacker.</li>
<li>Attacker supplies verification code and gets into your account.</li>
</ol>

<p>Do you notice the missing step there?</p>

<p>At no point does the attacker "infiltrate" your handset. Your handset is still in your possession. The SIM is dead, but that doesn't give the attacker access to the phone itself. There is simply <strong>no way</strong> for someone to put a new SIM into their phone and automatically get access to your device.</p>

<p>Try it now. Take your SIM out of your phone and put it into a new one. Do all of your apps suddenly appear? Are your usernames and passwords visible to you? No.</p>

<p>There are ways to transfer your data from an <a href="https://support.apple.com/en-gb/HT210216">iPhone</a> or <a href="https://support.google.com/android/answer/13761358?hl=en">Android</a> - but they require a lot more work than swapping a SIM.</p>

<p>So how did the attacker know which websites to target and what username to use?</p>

<h2 id="what-probably-happened"><a href="https://shkspr.mobi/blog/2025/04/thats-not-how-a-sim-swap-attack-works/#what-probably-happened">What (Probably) Happened</a></h2>

<p>Let's assume the person in the article didn't have malware on their device and hadn't handed over all their details to a cold caller.</p>

<p>The most obvious answer is that the attacker <em>already</em> knew the victim's email address. Maybe the victim gave out their phone number and email to some dodgy site, or they're listed on their contact page, or something like that.</p>

<p>The attacker now has two routes.</p>

<p>First is "hit and hope". They try the email address on hundreds of popular sites' password reset page until they get a match. That's time-consuming given the vast volume of websites.</p>

<p>Second is targetting your email. If the attacker can get into your email, they can see which sites you use, who your bank is, and where you shop.  They can target those specific sites, perform a password reset, and get your details.</p>

<p>I strongly suspect it is the latter which has happened. The swapped SIM was used to reset the victim's email password. Once in the email, all the accounts were easily found. At no point was the handset broken into.</p>

<h2 id="what-can-i-do-to-protect-myself"><a href="https://shkspr.mobi/blog/2025/04/thats-not-how-a-sim-swap-attack-works/#what-can-i-do-to-protect-myself">What can I do to protect myself?</a></h2>

<p>It is important to realise that <a href="https://shkspr.mobi/blog/2024/03/theres-nothing-you-can-do-to-prevent-a-sim-swap-attack/">there's nothing you can do to prevent a SIM-swap attack</a>! Your phone company is probably incompetent and their staff can easily be bribed. You do not control your phone number. If you get hit by a SIM swap, it almost certainly isn't your fault.</p>

<p>So here are some practical steps anyone can take to reduce the likelihood and effectiveness of this class of attack:</p>

<ul>
<li>Remember that <a href="https://shkspr.mobi/blog/2020/03/its-ok-to-lie-to-wifi-providers/">it's OK to lie to WiFi providers</a> and other people who ask for your details. You don't need to give someone your email for a receipt. You don't need to hand over your real phone number on a survey. This is the most important thing you can do.</li>
<li>Try to hack yourself. How easy would it be for an attacker who had stolen your phone number to also steal your email address? Open up a private browser window and try to reset your email password. What do you notice? How could you secure yourself better?</li>
<li>Don't use SMS for two-factor authentication. If you are given a choice of 2FA methods, use a dedicated app. If the only option you're given is SMS - contact the company to complain, or leave for a different provider.</li>
<li>Don't rely on a <a href="https://bsky.app/profile/scientits.bsky.social/post/3lmz2zaxkf22k">setting a PIN for your SIM</a>. The PIN only protects the physical SIM from being moved to a new device; it does nothing to stop your number being ported to a new SIM.</li>
<li>Finally, realise that professional criminals only need to be lucky once but you need to be lucky all the time.</li>
</ul>

<p>Stay safe out there.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=59603&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/04/thats-not-how-a-sim-swap-attack-works/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[FobCam '25 - All my MFA tokens on one page]]></title>
		<link>https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/</link>
					<comments>https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Fri, 11 Apr 2025 11:34:34 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[2fa]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[MFA]]></category>
		<category><![CDATA[Satire (Probably)]]></category>
		<category><![CDATA[security]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=59334</guid>

					<description><![CDATA[Some ideas are timeless. Back in 2004, an anonymous genius set up &#34;FobCam&#34;. Tired of having to carry around an RSA SecurID token everywhere, our hero simply left the fob at home with an early webcam pointing at it. And then left the page open for all to see.    Security expert Bruce Schneier approved of this trade-off between security and usability - saying what we&#039;re all thinking:  Here’s a guy w…]]></description>
										<content:encoded><![CDATA[<p>Some ideas are timeless. Back in 2004, an anonymous genius set up "<a href="https://web.archive.org/web/20060215092922/http://fob.webhop.net/">FobCam</a>". Tired of having to carry around an RSA SecurID token everywhere, our hero simply left the fob at home with an early webcam pointing at it. And then left the page open for all to see.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/04/FobCam-fs8.png" alt="Website with a grainy webcam photo of a SecurID fob." width="512" class="aligncenter size-full wp-image-59341">

<p>Security expert Bruce Schneier approved<sup id="fnref:🫠"><a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fn:🫠" class="footnote-ref" title="🫠" role="doc-noteref">0</a></sup> of this trade-off between security and usability - saying what we're all thinking:</p>

<blockquote><p>Here’s a guy who has a webcam pointing at his SecurID token, so he doesn’t have to remember to carry it around. Here’s the strange thing: unless you know who the webpage belongs to, it’s still good security.
<a href="https://www.schneier.com/crypto-gram/archives/2004/0815.html#:~:text=webcam">Crypto-Gram - August 15, 2004</a></p></blockquote>

<p>Nowadays, we have to carry dozens of these tokens with us. Although, unlike the poor schmucks of 2004, we have an app for that. But I don't always have access to my phone. Sometimes I'm in a secure location where I can't access my electronics. Sometimes my phone gets stolen, and I need to log into Facebook to whinge about it. Sometimes I just can't be bothered to remember which fingerprint unlocks my phone<sup id="fnref:🖕"><a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fn:🖕" class="footnote-ref" title="🖕" role="doc-noteref">1</a></sup>.</p>

<p>Using the <a href="https://shkspr.mobi/blog/2025/03/using-the-web-crypto-api-to-generate-totp-codes-in-javascript-without-3rd-party-libraries/">Web Crypto API, it is easy to Generate TOTP Codes in JavaScript directly in the browser</a>.  So here are all my important MFA tokens. If I ever need to log in somewhere, I can just visit this page and grab the code I need<sup id="fnref:🙃"><a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fn:🙃" class="footnote-ref" title="🙃" role="doc-noteref">2</a></sup>.</p>

<h2 id="all-my-important-codes"><a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#all-my-important-codes">All My Important Codes</a></h2>

<table>
<tbody><tr><td><img src="https://edent.github.io/SuperTinyIcons/images/svg/github.svg" width="100" title="Github"></td><td id="otp0"></td></tr>
<tr><td><img src="https://edent.github.io/SuperTinyIcons/images/svg/bitwarden.svg" width="100" title="BitWarden"></td><td id="otp1"></td></tr>
<tr><td><img src="https://edent.github.io/SuperTinyIcons/images/svg/apple.svg" width="100" title="Apple"></td><td id="otp2"></td></tr>
<tr><td><img src="https://edent.github.io/SuperTinyIcons/images/svg/ebay.svg" width="100" title="ebay"></td><td id="otp3"></td></tr>
<tr><td><img src="https://edent.github.io/SuperTinyIcons/images/svg/amazon.svg" width="100" title="Amazon"></td><td id="otp4"></td></tr>
<tr><td><img src="https://edent.github.io/SuperTinyIcons/images/svg/npm.svg" width="100" title="NPM"></td><td id="otp5"></td></tr>
<tr><td><img src="https://edent.github.io/SuperTinyIcons/images/svg/paypal.svg" width="100" title="PayPal"></td><td id="otp6"></td></tr>
<tr><td><img src="https://edent.github.io/SuperTinyIcons/images/svg/facebook.svg" width="100" title="Facebook"></td><td id="otp7"></td></tr>
<tr><td><img src="https://edent.github.io/SuperTinyIcons/images/svg/zoom.svg" width="100" title="Zoom"></td><td id="otp8"></td></tr>
<tr><td><img src="https://edent.github.io/SuperTinyIcons/images/svg/linkedin.svg" width="100" title="LinkedIn"></td><td id="otp9"></td></tr>
</tbody></table>

<h2 id="what-the-actual-fuck"><a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#what-the-actual-fuck">What The <em>Actual</em> Fuck?</a></h2>

<p>A 2007 paper called <a href="https://cups.cs.cmu.edu/soups/2007/proceedings/p64_bauer.pdf">Lessons learned from the deployment of a smartphone-based access-control system</a> looked at whether fobs met the needs of their users:</p>

<blockquote><p>However, we observed that end users tend to be most concerned about how convenient [fobs] are to use. There are many examples of end users of widely used access-control technologies readily sacrificing security for convenience. For example, it is well known that users often write their passwords on post-it notes and stick them to their computer monitors. Other users are more inventive: a good example is the user who pointed a webcam at his fob and published the image online so he would not have to carry the fob around.</p></blockquote>

<p>As for Schneier's suggestion that anonymity added protection, a contemporary report noted that <a href="https://www.schneier.com/crypto-gram/archives/2004/0915.html#:~:text=Fobcam">the owner of the FobCam site was trivial to identify</a><sup id="fnref:dox"><a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fn:dox" class="footnote-ref" title="The neologism &quot;doxing&quot; hadn't yet been invented." role="doc-noteref">3</a></sup>.</p>

<p>Every security system involves trade-offs. I have a password manager, but with over a thousand passwords in it, the process of navigating and maintaining becomes a burden. <a href="https://shkspr.mobi/blog/2020/08/i-have-4-2fa-coverage/">The number of 2FA tokens I have is also rising</a>. All of these security factors need backing up. Those back-ups need testing<sup id="fnref:back"><a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fn:back" class="footnote-ref" title="As was written by the prophets: &quot;Only wimps use tape backup: real men just upload their important stuff on ftp, and let the rest of the world mirror it&quot;" role="doc-noteref">4</a></sup>. It is an endless cycle of drudgery.</p>

<p>What's a rational user supposed to do<sup id="fnref:rat"><a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fn:rat" class="footnote-ref" title="I in no way imply that I am rational." role="doc-noteref">5</a></sup>? I suppose I could buy a couple of hardware keys, keep one in an off-site location, but somehow keep both in sync, and hope that a firmware-update doesn't brick them.</p>

<p>Should I just upload all of my passwords, tokens, secrets, recovery codes, passkeys, and biometrics<sup id="fnref:bro"><a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fn:bro" class="footnote-ref" title="Just one more factor, that'll fix security, just gotta add one more factor bro." role="doc-noteref">6</a></sup> into the cloud?</p>

<p>The cloud is just someone else's computer. This website is <em>my</em> computer. So I'm going to upload all my factors here. What's the worst that could happen<sup id="fnref:🤯"><a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fn:🤯" class="footnote-ref" title="This is left as an exercise for the reader." role="doc-noteref">7</a></sup>.</p>

<script>async function generateTOTP( 
    base32Secret = "QWERTY", 
    interval = 30, 
    length = 6, 
    algorithm = "SHA-1" ) {
    
    //  Decode the secret
    //  The Base32 Alphabet is specified at https://datatracker.ietf.org/doc/html/rfc4648#section-6
    const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
    let bits = "";
    
    //  Some secrets are padded with the `=` character. Remove padding.
    //  https://datatracker.ietf.org/doc/html/rfc3548#section-2.2
    base32Secret = base32Secret.replace( /=+$/, "" )

    //  Loop through the trimmed secret
    for ( let char of base32Secret ) {
        //  Ensure the secret's characters are upper case
        const value = alphabet.indexOf( char.toUpperCase() );

        //  If the character doesn't appear in the alphabet.
        if (value === -1) throw new Error( "Invalid Base32 character" );
        
        //  Binary representation of where the character is in the alphabet
        bits += value.toString( 2 ).padStart( 5, "0" );
    }

    //  Turn the bits into bytes
    let bytes = [];
    //  Loop through the bits, eight at a time
    for ( let i = 0; i < bits.length; i += 8 ) {
        if ( bits.length - i >= 8 ) {
                bytes.push( parseInt( bits.substring( i, i + 8 ), 2 ) );
        }
    }

    //  Turn those bytes into an array
    const decodedSecret = new Uint8Array( bytes );
    
    //  Number of seconds since Unix Epoch
    const timeStamp = Date.now() / 1000; 

    //  Number of intervals since Unix Epoch
    //  https://datatracker.ietf.org/doc/html/rfc6238#section-4.2
    const timeCounter = Math.floor( timeStamp / interval );

    //  Number of intervals in hexadecimal
    const timeHex = timeCounter.toString( 16 );

    //  Left-Pad with 0
    const paddedHex = timeHex.padStart( 16, "0" );

    //  Set up a buffer to hold the data
    const timeBuffer = new ArrayBuffer( 8 );
    const timeView   = new DataView( timeBuffer );
    
    //  Take the hex string, split it into 2-character chunks 
    const timeBytes = paddedHex.match( /.{1,2}/g ).map(
        //  Convert to bytes
        byte => parseInt( byte, 16 )
    );

    //  Write each byte into timeBuffer.
    for ( let i = 0; i < 8; i++ ) {
         timeView.setUint8(i, timeBytes[i]);
    }
    
    //  Use Web Crypto API to generate the HMAC key
    //  https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey
    const key = await crypto.subtle.importKey(
        "raw",
        decodedSecret,
        { 
            name: "HMAC", 
            hash: algorithm 
        },
        false,
        ["sign"]
    );

    //  Sign the timeBuffer with the generated HMAC key
    //  https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/sign
    const signature = await crypto.subtle.sign( "HMAC", key, timeBuffer );
    
    //  Get HMAC as bytes
    const hmac = new Uint8Array( signature );

    //  https://datatracker.ietf.org/doc/html/rfc4226#section-5.4
    //  Use the last byte to generate the offset
    const offset = hmac[ hmac.length - 1 ] & 0x0f;

    //  Bit Twiddling operations
    const binaryCode = 
        ( ( hmac[ offset     ] & 0x7f ) << 24 ) |
        ( ( hmac[ offset + 1 ] & 0xff ) << 16 ) |
        ( ( hmac[ offset + 2 ] & 0xff ) <<  8 ) |
        ( ( hmac[ offset + 3 ] & 0xff ) );

    //  Turn the binary code into a decimal string
    const stringOTP = binaryCode.toString();

    //  Count backwards from the last character for the length of the code
    let otp = stringOTP.slice( -length)

    //  Pad with 0 to full length
    otp = otp.padStart( length, "0" );

    //  All done!
    return otp;
}
//  Placeholder for OTPs
var otps = [];

//  Do you really think these are my genuine codes? At least one of them is. But which?
var otpData = 
    [
        {
            "algorithm"  : "SHA1",
            "digits"     :  6,
            "period"     : 15,
            "secret"     : "IPT5TRO7VFK66M6SHUJ7XZNM2U6IZZ4L"
        },
        {
            "algorithm"  : "SHA1",
            "digits"     :  6,
            "period"     : 15,
            "secret"     : "EXGKOX26KMDSTL6KM3BYMPXXDDKNQEYM"
        },
        {
            "algorithm"  : "SHA1",
            "digits"     :  6,
            "period"     : 15,
            "secret"     : "UGVGXRQFHY62OWI5SGSTZLIQUMXTTVME"
        },
        {
            "algorithm"  : "SHA1",
            "digits"     :  6,
            "period"     : 15,
            "secret"     : "Y4UHVLFIZZZK7ENDYZ4O3ZZI2QWUJI37"
        },
        {
            "algorithm"  : "SHA1",
            "digits"     :  6,
            "period"     : 15,
            "secret"     : "Z2KDRL4ELOCDALT3OSNUK65Z2KPOWGUL"
        },
        {
            "algorithm"  : "SHA1",
            "digits"     :  6,
            "period"     : 15,
            "secret"     : "OWRQKSCBLRUZXYXLXIDATUK6UTG3CPVV"
        },
        {
            "algorithm"  : "SHA1",
            "digits"     :  6,
            "period"     : 15,
            "secret"     : "XQLSEGNYPBMVK35ZMDTVN5GFOZB46WJJ"
        },
        {
            "algorithm"  : "SHA1",
            "digits"     :  6,
            "period"     : 15,
            "secret"     : "M3KVKGRB2WVWOZXN437EMF2MS36G75IR",
            "Comment"    : "This is genuinely my Twitter TOTP secret - although the period should be 30. But what's the password? There's a clue somewhere in this source code!",
        },
        {
            "algorithm"  : "SHA1",
            "digits"     :  6,
            "period"     : 15,
            "secret"     : "3EMER2B6YXIFMMAY5XBYLNF4NSEGJXCU"
        },
        {
            "algorithm"  : "SHA1",
            "digits"     :  6,
            "period"     : 15,
            "secret"     : "ZML6O5K7QSVFE5QIWNFFT7BIZI7PBHNV"
        }
    ]


var i = 0;

otpData.forEach (
    item => {
        //  Add OTP
        otps[i] = item;
        i++;
    }
);

//  Generate TOTP codes
async function update() {
    for (var i = 0; i < otps.length; i++){
            //  Convert the algorithm
            //  The algorithm name is different for TOTP and Web Crypto(!)
            algorithm = "SHA-1";
            
            document.getElementById( "otp" + i).innerHTML = await generateTOTP( 
                otps[i]["secret"], 
                otps[i]["period"], 
                otps[i]["digits"], 
                algorithm
            );
    }
}
//  Update every second
setInterval(update, 1000);

</script>

<div id="footnotes" role="doc-endnotes">
<hr aria-label="Footnotes">
<ol start="0">

<li id="fn:🫠">
<p>🫠&nbsp;<a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fnref:🫠" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:🖕">
<p>🖕&nbsp;<a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fnref:🖕" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:🙃">
<p>🙃&nbsp;<a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fnref:🙃" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:dox">
<p>The neologism "doxing" hadn't yet been invented.&nbsp;<a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fnref:dox" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:back">
<p>As was written by the prophets: "<a href="https://lkml.iu.edu/hypermail/linux/kernel/9607.2/0292.html">Only wimps use tape backup: <em>real</em> men just upload their important stuff on ftp, and let the rest of the world mirror it</a>"&nbsp;<a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fnref:back" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:rat">
<p>I in no way imply that I am rational.&nbsp;<a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fnref:rat" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:bro">
<p>Just one more factor, that'll fix security, just gotta add one more factor bro.&nbsp;<a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fnref:bro" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:🤯">
<p>This is left as an exercise for the reader.&nbsp;<a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fnref:🤯" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

</ol>
</div>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=59334&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[How to prevent Payment Pointer fraud]]></title>
		<link>https://shkspr.mobi/blog/2025/03/how-to-prevent-payment-pointer-fraud/</link>
					<comments>https://shkspr.mobi/blog/2025/03/how-to-prevent-payment-pointer-fraud/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sat, 29 Mar 2025 12:34:31 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[dns]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[standards]]></category>
		<category><![CDATA[WebMonetization]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=59172</guid>

					<description><![CDATA[There&#039;s a new Web Standard in town! Meet WebMonetization - it aims to be a low effort way to help users passively pay website owners.  The pitch is simple.  A website owner places a single new line in their HTML&#039;s &#60;head&#62; - something like this:  &#60;link rel=&#34;monetization&#34; href=&#34;https://wallet.example.com/edent&#34; /&#62;   That address is a &#34;Payment Pointer&#34;.  As a user browses the web, their browser takes …]]></description>
										<content:encoded><![CDATA[<p>There's a new Web Standard in town! Meet <a href="https://webmonetization.org">WebMonetization</a> - it aims to be a low effort way to help users passively pay website owners.</p>

<p>The pitch is simple.  A website owner places a single new line in their HTML's <code>&lt;head&gt;</code> - something like this:</p>

<pre><code class="language-html">&lt;link rel="monetization" href="https://wallet.example.com/edent" /&gt;
</code></pre>

<p>That address is a "<a href="https://paymentpointers.org/">Payment Pointer</a>".  As a user browses the web, their browser takes note of all the sites they've visited. At the end of the month, the funds in the user's digital wallet are split proportionally between the sites which have enabled WebMonetization. The user's budget is under their control and there are various technical measures to stop websites hijacking funds.</p>

<p>This could be revolutionary<sup id="fnref:coil"><a href="https://shkspr.mobi/blog/2025/03/how-to-prevent-payment-pointer-fraud/#fn:coil" class="footnote-ref" title="To be fair, Coil tried this in 2020 and it didn't take off. But the new standard has a lot less cryptocurrency bollocks, so maybe it'll work this time?" role="doc-noteref">0</a></sup>.</p>

<p>But there are some interesting fraud angles to consider.  Let me give you a couple of examples.</p>

<h2 id="pointer-hijacking"><a href="https://shkspr.mobi/blog/2025/03/how-to-prevent-payment-pointer-fraud/#pointer-hijacking">Pointer Hijacking</a></h2>

<p>Suppose I hacked into a popular site like BBC.co.uk and surreptitiously included my link in their HTML. Even if I was successful for just a few minutes, I could syphon off a significant amount of money.</p>

<p>At the moment, the WebMonetization plugin <em>only</em> looks at the page's HTML to find payment pointers.  There's no way to say "This site doesn't use WebMonetization" or an out-of-band way to signal which Payment Pointer is correct. Obviously there are lots of ways to profit from hacking a website - but most of them are ostentatious or require the user to interact.  This is subtle and silent.</p>

<p>How long would it take you to notice that a single meta element had snuck into some complex markup? When you discover it, what can you do? Money sent to that wallet can be transferred out in an instant. You might be able to get the wallet provider to freeze the funds or suspend the account, but that may not get you any money back.</p>

<p>Similarly, a <a href="https://lifehacker.com/tech/honey-influencer-scam-explained">Web Extension like Honey</a> could re-write the page's source code to remove or change an existing payment pointer.</p>

<h3 id="possible-solutions"><a href="https://shkspr.mobi/blog/2025/03/how-to-prevent-payment-pointer-fraud/#possible-solutions">Possible Solutions</a></h3>

<p>Perhaps the username associated with a Payment Pointer should be that of the website it uses?  something like <code>href="https://wallet.example.com/shkspr.mobi"</code></p>

<p>That's superficially attractive, but comes with issues.  I might have several domains - do I want to create a pointer for each of them?</p>

<p>There's also a legitimate use-case for having my pointer on someone else's site. Suppose I write a guest article for someone - their website might contain:</p>

<pre><code class="language-html">&lt;link rel="monetization" href="https://wallet.example.com/edent" /&gt;
&lt;link rel="monetization" href="https://wallet.coin_base.biz/BigSite" /&gt;
</code></pre>

<p>Which would allow us to split the revenue.</p>

<p>Similarly, a site like GitHub might let me use my Payment Pointer when people are visiting my specific page.</p>

<p>So, perhaps site owners should add a <a href="https://en.wikipedia.org/wiki/Well-known_URI">.well-known directive</a> which lists acceptable Pointers? Well, if I have the ability to add arbitrary HTML to a site, I might also be able to upload files. So it isn't particularly robust protection.</p>

<p>Alright, what are other ways typically used to prove the legitimacy of data? DNS maybe? As <a href="https://knowyourmeme.com/memes/one-more-lane-bro-one-more-lane-will-fix-it">the popular meme goes</a>:</p>

<blockquote class="social-embed" id="social-embed-114213713873874536" lang="en" itemscope="" itemtype="https://schema.org/SocialMediaPosting"><header class="social-embed-header" itemprop="author" itemscope="" itemtype="https://schema.org/Person"><a href="https://infosec.exchange/@atax1a" class="social-embed-user" itemprop="url"><img class="social-embed-avatar" src="https://media.infosec.exchange/infosec.exchange/accounts/avatars/109/323/500/710/698/443/original/20fd7265ad1541f5.png" alt="" itemprop="image"><div class="social-embed-user-names"><p class="social-embed-user-names-name" itemprop="name">@atax1a@infosec.exchange</p>mx alex tax1a - 2020 (5)</div></a><img class="social-embed-logo" alt="Mastodon" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-label='Mastodon' role='img' viewBox='0 0 512 512' fill='%23fff'%3E%3Cpath d='m0 0H512V512H0'/%3E%3ClinearGradient id='a' y2='1'%3E%3Cstop offset='0' stop-color='%236364ff'/%3E%3Cstop offset='1' stop-color='%23563acc'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M317 381q-124 28-123-39 69 15 149 2 67-13 72-80 3-101-3-116-19-49-72-58-98-10-162 0-56 10-75 58-12 31-3 147 3 32 9 53 13 46 70 69 83 23 138-9'/%3E%3Cpath d='M360 293h-36v-93q-1-26-29-23-20 3-20 34v47h-36v-47q0-31-20-34-30-3-30 28v88h-36v-91q1-51 44-60 33-5 51 21l9 15 9-15q16-26 51-21 43 9 43 60'/%3E%3C/svg%3E"></header><section class="social-embed-text" itemprop="articleBody"><p><span class="h-card" translate="no"><a href="https://mastodon.social/@jwz" class="u-url mention" rel="nofollow noopener" target="_blank">@<span>jwz</span></a></span> <span class="h-card" translate="no"><a href="https://toad.social/@grumpybozo" class="u-url mention" rel="nofollow noopener" target="_blank">@<span>grumpybozo</span></a></span> just one more public key in a TXT record, that'll fix email, just gotta add one more TXT record bro</p><div class="social-embed-media-grid"></div></section><hr class="social-embed-hr"><footer class="social-embed-footer"><a href="https://infosec.exchange/@atax1a/114213713873874536"><span aria-label="198 likes" class="social-embed-meta">❤️ 198</span><span aria-label="5 replies" class="social-embed-meta">💬 5</span><span aria-label="85 reposts" class="social-embed-meta">🔁 85</span><time datetime="2025-03-23T20:49:28.047Z" itemprop="datePublished">20:49 - Sun 23 March 2025</time></a></footer></blockquote>

<p>Someone with the ability to publish on a website is <em>less</em> likely to have access to DNS records. So having (yet another) DNS record could provide some protection. But DNS is tricky to get right, annoying to update, and a pain to repeatedly configure if you're constantly adding and removing legitimate users.</p>

<h2 id="reputation-hijacking"><a href="https://shkspr.mobi/blog/2025/03/how-to-prevent-payment-pointer-fraud/#reputation-hijacking">Reputation Hijacking</a></h2>

<p>Suppose the propaganda experts in The People's Republic of Blefuscu decide to launch a fake site for your favourite political cause. It contains all sorts of horrible lies about a political candidate and tarnishes the reputation of something you hold dear.  The sneaky tricksters put in a Payment Pointer which is the same as the legitimate site.</p>

<p>"This must be an official site," people say. "Look! It even funnels money to the same wallet as the other official sites!"</p>

<p>There's no way to disclaim money sent to you.  Perhaps a political opponent operates an illegal Bonsai Kitten farm - but puts your Payment Pointer on it.</p>

<p>"I don't squash kittens into jars!" You cry as they drag you away. The police are unconvinced "Then why are you profiting from it?"</p>

<h3 id="possible-solutions"><a href="https://shkspr.mobi/blog/2025/03/how-to-prevent-payment-pointer-fraud/#possible-solutions">Possible Solutions</a></h3>

<p>A wallet provider needs to be able to list which sites are <em>your</em> sites.</p>

<p>You log in to your wallet provider and fill in a list of websites you want your Payment Pointer to work on. Add your blog, your recipe site, your homemade video forum etc.  When a user browses a website, they see the Payment Pointer and ask it for a list of valid sites. If "BonsaiKitten.biz" isn't on there, no payment is sent.</p>

<p>Much like OAuth, there is an administrative hassle to this. You may need to regularly update the sites you use, and hope that your forgetfulness doesn't cost you in lost income.</p>

<h2 id="final-thoughts"><a href="https://shkspr.mobi/blog/2025/03/how-to-prevent-payment-pointer-fraud/#final-thoughts">Final Thoughts</a></h2>

<p>I'm moderately excited about WebMonetization. If it lives up to its promises, it could unleash a new wave of sustainable creativity across the web. If it is easier to make micropayments or donations to sites you like, without being subject to the invasive tracking of adverts, that would be brilliant.</p>

<p>The problems I've identified above are (I hope) minor. Someone sending you money without your consent may be concerning, but there's not much of an economic incentive to enrich your foes.</p>

<p>Think I'm wrong? Reckon you've found another fraudulent avenue? Want to argue about whether this is a likely problem? Stick a comment in the box.</p>

<div id="footnotes" role="doc-endnotes">
<hr aria-label="Footnotes">
<ol start="0">

<li id="fn:coil">
<p>To be fair, <a href="https://shkspr.mobi/blog/2020/10/adding-web-monetization-to-your-site-using-coil/">Coil tried this in 2020</a> and it didn't take off. But the new standard has a lot less cryptocurrency bollocks, so maybe it'll work this time?&nbsp;<a href="https://shkspr.mobi/blog/2025/03/how-to-prevent-payment-pointer-fraud/#fnref:coil" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

</ol>
</div>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=59172&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/03/how-to-prevent-payment-pointer-fraud/feed/</wfw:commentRss>
			<slash:comments>9</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Towards a test-suite for TOTP codes]]></title>
		<link>https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/</link>
					<comments>https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sun, 02 Mar 2025 12:34:39 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[2fa]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[HTOP]]></category>
		<category><![CDATA[MFA]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[totp]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=58593</guid>

					<description><![CDATA[Because I&#039;m a massive nerd, I actually try to read specification documents. As I&#039;ve ranted ad nauseam before, the current TOTP spec is irresponsibly obsolete.  The three major implementations of the spec - Google, Apple, and Yubico - all subtly disagree on how it should be implemented. Every other MFA app has their own idiosyncratic variants. The official RFC is infuriatingly vague. That&#039;s no…]]></description>
										<content:encoded><![CDATA[<p>Because I'm a massive nerd, I <em>actually try to read</em> specification documents. As I've ranted <i lang="la">ad nauseam</i> before, the current TOTP<sup id="fnref:totp"><a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#fn:totp" class="footnote-ref" title="Time-based One Time Passwords. Not the TV show you remember from your youth, grandad." role="doc-noteref">0</a></sup> spec is <a href="https://shkspr.mobi/blog/2025/02/the-least-secure-totp-code-possible/">irresponsibly obsolete</a>.</p>

<p>The three major implementations of the spec - <a href="https://github.com/google/google-authenticator/wiki/Key-Uri-Format">Google</a>, <a href="https://developer.apple.com/documentation/authenticationservices/securing-logins-with-icloud-keychain-verification-codes#3795996">Apple</a>, and <a href="https://docs.yubico.com/yesdk/users-manual/application-oath/uri-string-format.html">Yubico</a> - all subtly disagree on how it should be implemented. Every other MFA app has their own idiosyncratic variants. The <a href="https://datatracker.ietf.org/doc/html/rfc6238">official RFC is infuriatingly vague</a>. That's no good for a security specification. Multiple implementations are great, multiple interpretations are not.</p>

<p>So I've <a href="https://edent.codeberg.page/TOTP_Test_Suite/">built a nascent test suite</a> - you can use it to see if your favourite app can correctly implement the TOTP standard.</p>

<p><a href="https://edent.codeberg.page/TOTP_Test_Suite/"><img src="https://shkspr.mobi/blog/wp-content/uploads/2025/03/TOTP-Tests-fs8.png" alt="Screenshot showing a QR code and numeric codes." width="1024" height="813" class="aligncenter size-full wp-image-58598"></a></p>

<p>Please do contribute tests and / or feedback.</p>

<p>Here's what the standard <em>actually</em> says - see if you can find apps which don't implement it correctly.</p>

<h2 id="background"><a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#background">Background</a></h2>

<p>Time-based One Time Passwords are based on HOTP - HMAC-Based One-Time Password.</p>

<p>HOTP uses counters; a new password is regularly generated. TOTP uses time as the counter. At the time of writing this post, there have been about 1,740,800,000 seconds since the UNIX Epoc. So a TOTP with an period of 30 seconds is on counter (1,740,800,000 ➗ 30) = 58,026,666.  Every 30 seconds, that counter increments by one.</p>

<h3 id="number-of-digits"><a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#number-of-digits">Number of digits</a></h3>

<p>How many digits should your 2FA token have? Google says 6 or 8. YubiCo graciously allows 7. Why those limits? Who knows!?</p>

<p><a href="https://datatracker.ietf.org/doc/html/rfc4226#section-5.4">The HOTP specification gives an <em>example</em> of 6 digits</a>.  The example generates a code of <code>0x50ef7f19</code> which, in decimal, is <code>1357872921</code>. It then takes the last 6 digits to produce the code <code>872921</code>.</p>

<p>The TOTP RFC says:</p>

<blockquote><p>Basically, the output of the HMAC-SHA-1 calculation is truncated to obtain user-friendly values</p>

<p><a href="https://datatracker.ietf.org/doc/html/rfc6238#section-1.2">1.2. Background</a></p></blockquote>

<p>But doesn't say how far to truncate.</p>

<p>There's nothing I can see in the spec that <em>prevents</em> an implementer using all 10.  The HOTP spec, however, <em>does</em> place a minimum requirement - but no maximum:</p>

<blockquote><p>Implementations MUST extract a 6-digit code at a minimum and possibly 7 and 8-digit code.
Depending on security requirements, Digit = 7 or more SHOULD be considered in order to extract a longer HOTP value.
<a href="https://datatracker.ietf.org/doc/html/rfc4226#section-5.3">RFC 4226 - 5.3. Generating an HOTP Value</a></p></blockquote>

<p>(As a minor point, the first digit is restricted to 0-2, so being 10 digits long isn't significantly stronger than 9 digits.)</p>

<p>Is a 4 digit code acceptable? The security might be weaker, but the usability is greater. Most apps will allow a <em>one</em> digit code to be returned. If no digits are specified, what should the default be?</p>

<h3 id="algorithm"><a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#algorithm">Algorithm</a></h3>

<p>The given algorithm in the HOTP spec is SHA-1.</p>

<blockquote><p>In order to create the HOTP value, we will use the HMAC-SHA-1 algorithm
<a href="https://datatracker.ietf.org/doc/html/rfc4226#section-5.2">RFC 4226 - 5.2.  Description</a></p></blockquote>

<p>As we now know, SHA-1 has some fundamental weaknesses. The spec comments (perhaps somewhat naïvely) about SHA-1:</p>

<blockquote><p>The new attacks on SHA-1 have no impact on the security of HMAC-SHA-1.
<a href="https://datatracker.ietf.org/doc/html/rfc4226#appendix-B.2">RFC 4226 - B.2.  HMAC-SHA-1 Status</a></p></blockquote>

<p>I daresay that's accurate. But the TOTP authors disagree and allow for some different algorithms to be used. The specification for HMAC says:</p>

<blockquote><p>HMAC can be used with <em>any</em> iterative cryptographic hash function, e.g., MD5, SHA-1
[Emphasis added]
<a href="https://datatracker.ietf.org/doc/html/rfc2104">RFC 2104 - HMAC: Keyed-Hashing for Message Authentication</a></p></blockquote>

<p>So most TOTP implementation allow SHA-1, SHA-256, and SHA-512.</p>

<blockquote><p>TOTP implementations MAY use HMAC-SHA-256 or HMAC-SHA-512 functions […] instead of the HMAC-SHA-1 function that has been specified for the HOTP computation
<a href="https://datatracker.ietf.org/doc/html/rfc6238#section-1.2">RFC 6238 - TOTP: Time-Based One-Time Password Algorithm</a></p></blockquote>

<p>But the HOTP spec goes on to say:</p>

<blockquote><p>Current candidates for such hash functions include SHA-1, MD5, RIPEMD-128/160.
These different realizations of HMAC will be denoted by HMAC-SHA1, HMAC-MD5, HMAC-RIPEMD
<a href="https://datatracker.ietf.org/doc/html/rfc2104#section-1">RFC 2104 - Introduction</a></p></blockquote>

<p>So, should your TOTP app be able to handle an MD5 HMAC, or even SHA3-384? Will it?  If no algorithm is specified, what should the default be?</p>

<h3 id="period"><a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#period">Period</a></h3>

<p>As discussed, this is what increments the counter for HOTP. The <a href="https://github.com/google/google-authenticator/wiki/Key-Uri-Format">Google Spec</a> says:</p>

<blockquote><p>The period parameter defines a period that a TOTP code will be valid for, in seconds. The default value is 30.</p></blockquote>

<p>The TOTP RFC says:</p>

<blockquote><p>We RECOMMEND a default time-step size of 30 seconds
<a href="https://datatracker.ietf.org/doc/html/rfc6238#section-5.2">5.2. Validation and Time-Step Size</a></p></blockquote>

<p>It doesn't make sense to have a negative number of second. But what about one second? What about a thousand? Lots of apps artificially restrict TOTP codes to 15, 30, or 60 seconds. But there's no specification to define a maximum or minimum value.</p>

<p>A user with mobility difficulties or on a high-latency connection probably wants a 5 minute validity period. Conversely, machine-to-machine communication can probably be done with a single-second (or lower) time period.</p>

<h3 id="secret"><a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#secret">Secret</a></h3>

<p>Google says the secret is</p>

<blockquote><p>an arbitrary key value encoded in Base32 according to RFC 3548. The padding specified in RFC 3548 section 2.2 is not required and should be omitted.</p></blockquote>

<p>Whereas Apple says it is:</p>

<blockquote><p>An arbitrary key value encoded in Base32. Secrets should be at least 160 bits.</p></blockquote>

<p>Can a shared secret be a single character? What about a thousand? Will padding characters cause a secret to be rejected or can they be safely stripped?</p>

<h3 id="label"><a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#label">Label</a></h3>

<p>The label allows you to have multiple codes for the same service. For example <code>Big Bank:Personal Account</code> and <code>Big Bank:Family Savings</code>.  The Google spec is slightly confusing:</p>

<blockquote><p>The issuer prefix and account name should be separated by a literal or url-encoded colon, and optional spaces may precede the account name. Neither issuer nor account name may themselves contain a colon.</p></blockquote>

<p>What happens if they are <em>not</em> URl encoded? What about Matrix accounts which use a colon in their account name? Why are spaces allowed to precede the account name? Is there any practical limit to the length of these strings?</p>

<p>If no label is specified, what should the default be?</p>

<h3 id="issuer"><a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#issuer">Issuer</a></h3>

<p>Google says this parameter is:</p>

<blockquote><p><strong>Strongly Recommended</strong> The issuer parameter is a string value indicating the provider or service this account is associated with, URL-encoded according to RFC 3986. If the issuer parameter is absent, issuer information may be taken from the issuer prefix of the label. If both issuer parameter and issuer label prefix are present, they should be equal.</p></blockquote>

<p>Apple merely says:</p>

<blockquote><p>The domain of the site or app. The password manager uses this field to suggest credentials when setting up a new code generator.</p></blockquote>

<p>Yubico equivocates with</p>

<blockquote><p>The issuer parameter is recommended, but it can be absent. Also, the issuer parameter and issuer string in label should be equal.</p></blockquote>

<p>If it isn't a domain, will Apple reject it? What happens if the issuer and the label don't match?</p>

<h2 id="next-steps"><a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#next-steps">Next Steps</a></h2>

<ul>
<li>If you're a user, <a href="https://codeberg.org/edent/TOTP_Test_Suite">please contribute tests</a> or give feedback.</li>
<li>If you're a developer, please check your app conforms to the specification.</li>
<li>If you're from Google, Apple, Yubico, or another security company - wanna help me write up a proper RFC so this doesn't cause issues in the future?</li>
</ul>

<div id="footnotes" role="doc-endnotes">
<hr aria-label="Footnotes">
<ol start="0">

<li id="fn:totp">
<p>Time-based One Time Passwords. Not the TV show you remember from your youth, grandad.&nbsp;<a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#fnref:totp" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

</ol>
</div>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=58593&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/feed/</wfw:commentRss>
			<slash:comments>11</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Using the Web Crypto API to Generate TOTP Codes in JavaScript Without 3rd Party Libraries]]></title>
		<link>https://shkspr.mobi/blog/2025/03/using-the-web-crypto-api-to-generate-totp-codes-in-javascript-without-3rd-party-libraries/</link>
					<comments>https://shkspr.mobi/blog/2025/03/using-the-web-crypto-api-to-generate-totp-codes-in-javascript-without-3rd-party-libraries/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sat, 01 Mar 2025 12:34:57 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[totp]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=58536</guid>

					<description><![CDATA[The Web Crypto API is, thankfully, nothing to do with scammy cryptocurrencies. Instead, it provides access to powerful cryptographic features which were previously only available in 3rd party tools.  So, is it possible to build a TOTP code generator without using any external JS libraries? Yes! And it is (relatively) simple.  Here&#039;s the code that I&#039;ve written. It is slightly verbose and contains…]]></description>
										<content:encoded><![CDATA[<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API">Web Crypto API</a> is, thankfully, nothing to do with scammy cryptocurrencies. Instead, it provides access to powerful cryptographic features which were previously only available in 3rd party tools.</p>

<p>So, is it possible to build a TOTP<sup id="fnref:sigh"><a href="https://shkspr.mobi/blog/2025/03/using-the-web-crypto-api-to-generate-totp-codes-in-javascript-without-3rd-party-libraries/#fn:sigh" class="footnote-ref" title="*sigh* Please don't be the boring dolt who makes a joke about Top of The Pops. Yes, I know they share the same initialism. And, yes, it's funny how nonce means something different in cryptography…" role="doc-noteref">0</a></sup> code generator without using <em>any</em> external JS libraries? Yes! And it is (relatively) simple.</p>

<p>Here's the code that I've written. It is slightly verbose and contains a lot of logging so you can see what it is doing. I've annotated it with links to the various specifications so you can see where some of the decisions come from. I've compared the output to several popular TOTP code generators and it <em>appears</em> to match. You probably shouldn't use this in production, and you should audit it thoroughly.</p>

<p>I'm sure there are bugs to be fixed and performance enhancements to be made. Feel free to leave a comment here <a href="https://codeberg.org/edent/TOTP_Test_Suite">or on the repo</a> if you spot anything.</p>

<p>I consider this code to be trivial but, if it makes you happy, you may consider it licensed under MIT.</p>

<pre><code class="language-js">async function generateTOTP( 
    base32Secret = "QWERTY", 
    interval = 30, 
    length = 6, 
    algorithm = "SHA-1" ) {

    //  Are the interval and length valid?
    if ( interval &lt;  1 ) throw new Error( "Interval is too short" );
    if ( length   &lt;  1 ) throw new Error( "Length is too low"     );
    if ( length   &gt; 10 ) throw new Error( "Length is too high"    );

    //  Is the algorithm valid?
    //  https://datatracker.ietf.org/doc/html/rfc6238#section-1.2
    algorithm = algorithm.toUpperCase();
    if ( algorithm.match( "SHA-1|SHA-256|SHA-384|SHA-512" ) == null ) throw new Error( "Algorithm not known" );

    //  Decode the secret
    //  The Base32 Alphabet is specified at https://datatracker.ietf.org/doc/html/rfc4648#section-6
    const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
    let bits = "";

    //  Some secrets are padded with the `=` character. Remove padding.
    //  https://datatracker.ietf.org/doc/html/rfc3548#section-2.2
    base32Secret = base32Secret.replace( /=+$/, "" )

    //  Loop through the trimmed secret
    for ( let char of base32Secret ) {
        //  Ensure the secret's characters are upper case
        const value = alphabet.indexOf( char.toUpperCase() );

        //  If the character doesn't appear in the alphabet.
        if (value === -1) throw new Error( "Invalid Base32 character" );

        //  Binary representation of where the character is in the alphabet
        bits += value.toString( 2 ).padStart( 5, "0" );
    }

    //  Turn the bits into bytes
    let bytes = [];
    //  Loop through the bits, eight at a time
    for ( let i = 0; i &lt; bits.length; i += 8 ) {
        if ( bits.length - i &gt;= 8 ) {
                bytes.push( parseInt( bits.substring( i, i + 8 ), 2 ) );
        }
    }

    //  Turn those bytes into an array
    const decodedSecret = new Uint8Array( bytes );
    console.log( "decodedSecret is " + decodedSecret )

    //  Number of seconds since Unix Epoch
    const timeStamp = Date.now() / 1000; 
    console.log( "timeStamp is " + timeStamp )

    //  Number of intervals since Unix Epoch
    //  https://datatracker.ietf.org/doc/html/rfc6238#section-4.2
    const timeCounter = Math.floor( timeStamp / interval );
    console.log( "timeCounter is " + timeCounter )

    //  Number of intervals in hexadecimal
    const timeHex = timeCounter.toString( 16 );
    console.log( "timeHex is " + timeHex )

    //  Left-Pad with 0
    paddedHex = timeHex.toString(2).padStart( 16, "0" );
    console.log( "paddedHex is " + paddedHex )

    //  Set up a buffer to hold the data
    const timeBuffer = new ArrayBuffer( 8 );
    const timeView   = new DataView( timeBuffer );

    //  Take the hex string, split it into 2-character chunks 
    const timeBytes = paddedHex.match( /.{1,2}/g ).map(
        //  Convert to bytes
        byte =&gt; parseInt( byte, 16 )
    );

    //  Write each byte into timeBuffer.
    for ( let i = 0; i &lt; 8; i++ ) {
         timeView.setUint8(i, timeBytes[i]);
    }
    console.log( "timeView is ",  new Uint8Array( timeView   ) );
    console.log( "timeBuffer is", new Uint8Array( timeBuffer ) );

    //  Use Web Crypto API to generate the HMAC key
    //  https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey
    const key = await crypto.subtle.importKey(
        "raw",
        decodedSecret,
        { 
            name: "HMAC", 
            hash: algorithm 
        },
        false,
        ["sign"]
    );

    //  Sign the timeBuffer with the generated HMAC key
    //  https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/sign
    const signature = await crypto.subtle.sign( "HMAC", key, timeBuffer );

    //  Get HMAC as bytes
    const hmac = new Uint8Array( signature );
    console.log( "hmac is ", hmac );

    //  https://datatracker.ietf.org/doc/html/rfc4226#section-5.4
    //  Use the last byte to generate the offset
    const offset = hmac[ hmac.length - 1 ] &amp; 0x0f;
    console.log( "offset is " + offset )

    //  Bit Twiddling operations
    const binaryCode = 
        ( ( hmac[ offset     ] &amp; 0x7f ) &lt;&lt; 24 ) |
        ( ( hmac[ offset + 1 ] &amp; 0xff ) &lt;&lt; 16 ) |
        ( ( hmac[ offset + 2 ] &amp; 0xff ) &lt;&lt;  8 ) |
        ( ( hmac[ offset + 3 ] &amp; 0xff ) );

    //  Turn the binary code into a decimal string
    stringOTP = binaryCode.toString();
    console.log( "stringOTP is " + stringOTP );

    //  Count backwards from the last character for the length of the code
    otp = stringOTP.slice( -length) 
    console.log( "otp is " + otp );
    //  Pad with 0 to full length
    otp = otp.padStart( length, "0" );
    console.log( "padded otp is " + otp );

    //  All done!
    return otp;
}


// Generate a TOTP code
( async () =&gt; {
    console.log( await generateTOTP( "4FCDTLHR446DPFCKUA46UFIAYTQIDSZ2", 30, 6, "SHA-1" ) );
} )();
</code></pre>

<p>It works with the three specified algorithms, generating between 1 and 10 digits, and works with any positive integer interval. Not all combinations are sensible; <a href="https://shkspr.mobi/blog/2025/02/the-least-secure-totp-code-possible/">a one digit code valid for two minutes would be silly</a>. But it is up to you to use this responsibly.</p>

<p>I hope I've shown that you don't need to rely on 3rd party libraries to do your cryptography; you can do it all in the browser instead.</p>

<p>You can <a href="https://codeberg.org/edent/TOTP_Test_Suite">grab the code from Codeberg</a>.</p>

<div id="footnotes" role="doc-endnotes">
<hr aria-label="Footnotes">
<ol start="0">

<li id="fn:sigh">
<p><em>*sigh*</em> Please don't be the boring dolt who makes a joke about Top of The Pops. Yes, I know they share the same initialism. And, yes, it's funny how <code>nonce</code> means something different in cryptography compared to British English.&nbsp;<a href="https://shkspr.mobi/blog/2025/03/using-the-web-crypto-api-to-generate-totp-codes-in-javascript-without-3rd-party-libraries/#fnref:sigh" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

</ol>
</div>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=58536&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/03/using-the-web-crypto-api-to-generate-totp-codes-in-javascript-without-3rd-party-libraries/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[The least secure TOTP code possible]]></title>
		<link>https://shkspr.mobi/blog/2025/02/the-least-secure-totp-code-possible/</link>
					<comments>https://shkspr.mobi/blog/2025/02/the-least-secure-totp-code-possible/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Mon, 24 Feb 2025 12:34:05 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[rant]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[standards]]></category>
		<category><![CDATA[totp]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=58360</guid>

					<description><![CDATA[If you use Multi-Factor Authentication, you&#039;ll be well used to scanning in QR codes which allow you to share a secret code with a website. These are known as Time-based One Time Passwords (TOTP).  As I&#039;ve moaned about before, TOTP has never been properly standardised. It&#039;s a mish-mash of half-finished proposals with no active development, no test suite, and no-one looking after it. Which is…]]></description>
										<content:encoded><![CDATA[<p>If you use Multi-Factor Authentication, you'll be well used to scanning in QR codes which allow you to share a secret code with a website. These are known as Time-based One Time Passwords (TOTP<sup id="fnref:pop"><a href="https://shkspr.mobi/blog/2025/02/the-least-secure-totp-code-possible/#fn:pop" class="footnote-ref" title="Yes! Just like Top of The Pops! The famous British TV show! Wow! I bet you're the first person in history to make that joke! Have a biscuit." role="doc-noteref">0</a></sup>).</p>

<p>As I've moaned about before, <a href="https://shkspr.mobi/blog/2022/05/why-is-there-no-formal-specification-for-otpauth-urls/">TOTP has never been properly standardised</a>. It's a mish-mash of half-finished proposals with no active development, no test suite, and no-one looking after it. Which is <em>exactly</em> what you want from a security specification, right?!</p>

<p>So let's try to find some edge-cases and see where things break down.</p>

<h2 id="one-punch-man"><a href="https://shkspr.mobi/blog/2025/02/the-least-secure-totp-code-possible/#one-punch-man">One Punch Man</a></h2>

<p>This is possibly the <em>least</em> secure TOTP code I could create. Scan it and see whether your app will accept it.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/02/ultra.png" alt="QR code." width="350" height="350" class="aligncenter size-full wp-image-58361">

<p>What makes it so crap?  There are three things which protect you when using TOTP.</p>

<ol>
<li>The shared secret. In this case, it is <code>abcdefghijklmno</code> - OK, that's not the easiest thing to guess, but it isn't exactly complex.</li>
<li>The amount time the code is valid for before changing. Most TOTP codes last 30 seconds, this lasts 120.</li>
<li>The length of the code. Most codes are 6 digits long. In theory, the spec allows 8 digits. This is 1. Yup. A single digit.</li>
</ol>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/02/totp-bitwarden-fs8.png" alt="BitWarden showing a single digit for 119 seconds." width="504" height="378" class="aligncenter size-full wp-image-58380">

<p>If you were thick enough to use this<sup id="fnref:noooooo"><a href="https://shkspr.mobi/blog/2025/02/the-least-secure-totp-code-possible/#fn:noooooo" class="footnote-ref" title="Please don't!" role="doc-noteref">1</a></sup>, an attacker would have a 1/10 chance of simply <em>guessing</em> your MFA code. If they saw you type it in, they'd have a couple of minutes in which to reuse it.</p>

<p>Can modern TOTP apps add this code? I <a href="https://mastodon.social/@Edent/114032994415288253">crowdsourced the answers</a>.</p>

<p>Surprisingly, a few apps accept it! Aegis, 1password, and BitWarden will happily store it and show you a 1 digit code for 120 seconds.</p>

<p>A few reject it. Authy, Google Authenticator, and OpenOTP claim the code is broken and won't add it.</p>

<p>But, weirdly, a few <em>interpret it incorrectly!</em> The native iOS app, Microsoft Authenticator, and KeepassXC store the code, but treat it as a 6 digit, 30 second code.</p>

<h2 id="do-the-right-thing"><a href="https://shkspr.mobi/blog/2025/02/the-least-secure-totp-code-possible/#do-the-right-thing">Do The Right Thing</a></h2>

<p>What is the right thing to do in this case? The code is outside the (very loosely defined) specification. <a href="https://lawsofux.com/postels-law/">Postel's Law</a> tells us that we should try our best to interpret malformed data - which is what Aegis and BitWarden do.</p>

<p>But, in a security context, that could be dangerous. Perhaps rejecting a dodgy code makes more sense?</p>

<p>What is absolutely daft<sup id="fnref:stronger"><a href="https://shkspr.mobi/blog/2025/02/the-least-secure-totp-code-possible/#fn:stronger" class="footnote-ref" title="I wanted to use the words &quot;utterly fucking stupid&quot; but I felt it was unprofessional." role="doc-noteref">2</a></sup> is ignoring the bits of the code you don't like and substituting your own data! Luckily, in a normal TOTP enrolment, the user has to enter a code to prove they've saved it correctly. Entering in a 6 digit code where only 1 is expected is likely to fail.</p>

<h2 id="were-only-human"><a href="https://shkspr.mobi/blog/2025/02/the-least-secure-totp-code-possible/#were-only-human">We're Only Human</a></h2>

<p>A one-digit code is ridiculous. But what about the other extreme? Would a 128-digit code be acceptable? For a human, no; it would be impossible to type in correctly. For a machine with a shared secret, it possibly makes sense.</p>

<p>On a high-latency connection or with users who may have mobility difficulties, a multi-minute timeframe could be sensible. For something of extremely high security, sub-30 seconds may be necessary.</p>

<p>But, again, the specification hasn't evolved to meet user needs. It is stagnant and decaying.</p>

<h2 id="whats-next"><a href="https://shkspr.mobi/blog/2025/02/the-least-secure-totp-code-possible/#whats-next">What's Next?</a></h2>

<p>There's an <a href="https://www.ietf.org/archive/id/draft-linuxgemini-otpauth-uri-00.html">draft proposal to tighten up to TOTP spec</a> which has expired.</p>

<p>It would be nice if the major security players came together to work out a <em>formal</em> and <em>complete</em> specification for this vital piece of security architecture. But I bet it won't ever happen.</p>

<ul>
<li><a href="https://github.com/google/google-authenticator/wiki/Key-Uri-Format">Google have archived their work on authentication standards</a>.</li>
<li><a href="https://developer.apple.com/documentation/authenticationservices/securing-logins-with-icloud-keychain-verification-codes#3795996">Apple points to Google's outdated spec</a>.</li>
<li><a href="https://docs.yubico.com/yesdk/users-manual/application-oath/uri-string-format.html">YubiCo's incompatible spec hasn't been updated in 4 years</a>.</li>
<li>The <a href="https://www.iana.org/assignments/uri-schemes/prov/otpauth">otpauth registration</a> lists a consortium called <a href="https://openauthentication.org">https://openauthentication.org</a> who don't appear to published anything in a decade.</li>
<li>Microsoft don't have any documentation whatsoever.</li>
</ul>

<p>So there you have it. We're told to rely on TOTP for our MFA - yet the major apps all disagree on how the standard should be implemented. This is a recipe for an eventual security disaster.</p>

<p>How do we fix it?</p>

<div id="footnotes" role="doc-endnotes">
<hr aria-label="Footnotes">
<ol start="0">

<li id="fn:pop">
<p>Yes! Just like Top of The Pops! The famous British TV show! Wow! I bet you're the first person in history to make that joke! Have a biscuit.&nbsp;<a href="https://shkspr.mobi/blog/2025/02/the-least-secure-totp-code-possible/#fnref:pop" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:noooooo">
<p>Please don't!&nbsp;<a href="https://shkspr.mobi/blog/2025/02/the-least-secure-totp-code-possible/#fnref:noooooo" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:stronger">
<p>I wanted to use the words "utterly fucking stupid" but I felt it was unprofessional.&nbsp;<a href="https://shkspr.mobi/blog/2025/02/the-least-secure-totp-code-possible/#fnref:stronger" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

</ol>
</div>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=58360&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/02/the-least-secure-totp-code-possible/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Review: Pebblebee Clip Universal - and Android "Find My Device" Tracker ★★★⯪☆]]></title>
		<link>https://shkspr.mobi/blog/2025/01/review-pebblebee-clip-universal-and-android-find-my-device-tracker/</link>
					<comments>https://shkspr.mobi/blog/2025/01/review-pebblebee-clip-universal-and-android-find-my-device-tracker/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sat, 11 Jan 2025 12:34:15 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[ble]]></category>
		<category><![CDATA[bluetooth]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[gadget]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[review]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=54516</guid>

					<description><![CDATA[Android is belatedly getting a Bluetooth tracker feature which doesn&#039;t rely on proprietary apps. Long-time readers will know that back in 2016 I reviewed both the Chipolo and the TinTag.  Both of those were adequate at finding things which were in range of your phone, but hopeless at finding lost items - because they required everyone to have a special app installed.  But now, under pressure from …]]></description>
										<content:encoded><![CDATA[<p>Android is belatedly getting a Bluetooth tracker feature which doesn't rely on proprietary apps. Long-time readers will know that back in 2016 I reviewed both the <a href="https://shkspr.mobi/blog/2016/11/review-chipolo-plus/">Chipolo</a> and the <a href="https://shkspr.mobi/blog/2016/06/tintag-unboxing-and-review/">TinTag</a>.  Both of those were adequate at finding things which were in range of your phone, but hopeless at finding lost items - because they required <em>everyone</em> to have a special app installed.</p>

<p>But now, under pressure from Apple's incredible Find My network, Google has started rolling out a similar service to modern Android phones. In <em>theory</em> it should be much better; Android has a higher market share than iOS in most parts of the world I'm interested in visiting. But Apple's monoculture means they can quickly roll out the network to a much higher range of devices than Google.</p>

<p>The Pebblebee "Universal" range works with both Apple and Android's networks. But, crucially, <em>not at the same time</em>. You can reset the device and swap it between your iPhone and Galaxy - but it won't connect to both networks simultaneously.</p>

<p>Hey, remember when Google and Apple collaborated so that Covid tracing apps were interoperable no matter the device? Good times, man! But, y'know, this is just for protecting property, not life. So we'll give them a pass…</p>

<p>This is what the Pebblebee Clip looks like.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2024/01/pebblebee-box.jpg" alt="Small plastic disk with a small metal ring." width="1024" height="1024" class="aligncenter size-full wp-image-55182">

<p>It's a fairly unobtrusive small disk. Clip it to a thing with the included clip, hide it in the lining, glue it to a device. The logo is a clickable button which is used for <a href="https://help.pebblebee.com/article/hx8kcsewp0-get-started-with-your-pebblebee-for-android">pairing the device</a>, resetting, and checking the battery.</p>

<p>It also comes with a ridiculously short USB-C-to-C cable which can only be used for charging.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2024/01/pebblebee-USB.jpg" alt="A USB-C cable that is only a couple of cm long." width="1024" height="768" class="aligncenter size-full wp-image-55184">

<p>Dump it and grab a longer cable from your big box of cables. Total e-Waste, shouldn't have been included.</p>

<p>When you tell the app to make the PebbleBee identify itself, you're rewarded with this display of loud beeps and disco lasers.</p>

<p></p><div style="width: 620px;" class="wp-video"><video class="wp-video-shortcode" id="video-54516-2" width="620" height="349" preload="metadata" controls="controls"><source type="video/mp4" src="https://shkspr.mobi/blog/wp-content/uploads/2024/01/pebblesmall.mp4?_=2"><a href="https://shkspr.mobi/blog/wp-content/uploads/2024/01/pebblesmall.mp4">https://shkspr.mobi/blog/wp-content/uploads/2024/01/pebblesmall.mp4</a></video></div><p></p>

<p>The lights are bright and the sound is piercing - especially considering its size. It fits neatly in a hand and is small enough to tuck away in a pocket.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2024/01/pebblebee-lights.jpg" alt="The disk has a USB-C socket at the bottom and flashing lights on the side." width="1024" height="768" class="aligncenter size-full wp-image-55183">

<p>But what's it like to use?</p>

<h2 id="pros"><a href="https://shkspr.mobi/blog/2025/01/review-pebblebee-clip-universal-and-android-find-my-device-tracker/#pros">Pros</a></h2>

<ul>
<li>USB-C rechargable. No more faffing about trying to find a new battery. No e-Waste. No worrying if it'll last an entire trip. Shove it into to any USB power source and you're good to go.</li>
<li>Loud beeper. One of the main reasons I got this was that it (reportedly) has the loudest speaker on the market. I can't compare it to others but it is certainly good enough for hearing in a crowded train carriage.</li>
<li>Lights. The sides light up - handy for giving you a visual cue as to where it is.</li>
<li>Small, light, and includes a keyring connector.</li>
<li>You can <a href="https://blog.google/products/android/android-find-my-device/#:~:text=Share%20accessories">share trackers between accounts</a>. My wife and I each have a suitcase. We don't just want to know where our own bag is - we both want to know where <em>both</em> bags are.</li>
</ul>

<h2 id="cons"><a href="https://shkspr.mobi/blog/2025/01/review-pebblebee-clip-universal-and-android-find-my-device-tracker/#cons">Cons</a></h2>

<p>The downsides of the device are minimal - depending on your use case.</p>

<ul>
<li>Not waterproof. Certainly water resistant - but the USB-C socket is an ingress point for fluids.</li>
<li>No Ultra Wide Band. That means you don't get a precise direction when looking for something - just the distance. UWB isn't supported on Google's "Find My Device" network right now, so this isn't a great loss.</li>
<li>No wireless charging.</li>
<li>Cost. Even in bulk, with a discount, they were £25 each.</li>
</ul>

<h2 id="security"><a href="https://shkspr.mobi/blog/2025/01/review-pebblebee-clip-universal-and-android-find-my-device-tracker/#security">Security</a></h2>

<p>Anyone who finds your tracker can <a href="https://help.pebblebee.com/article/aroje5h88v-how-to-factory-reset-a-clip-or-card">factory reset it</a>. I can't help but feel there should be a way to prevent that. But, to be honest, if a thief has found your token they can just throw it away or destroy it.</p>

<p>Firmware updates aren't available in the Google Find My app. So you'll need to <a href="https://help.pebblebee.com/article/ako3p1yfzd-fmd-update">use Pebblebee's own app</a>.</p>

<p>The USB-C port is for power only. They don't show up as a device when connected to a computer.</p>

<h2 id="testing"><a href="https://shkspr.mobi/blog/2025/01/review-pebblebee-clip-universal-and-android-find-my-device-tracker/#testing">Testing</a></h2>

<p>I wasn't able to <a href="https://github.com/GrapheneOS/os-issue-tracker/issues/4079">connect to the PebbleBee using GrapheneOS</a> - one of the downsides of using a hyper-secure version of Android.</p>

<p>I used a separate phone, but couldn't get the device to pair. I kept getting this message:</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2024/01/upgrade-fs8.png" alt="Error saying I need to upgrade my Android version." width="504" height="533" class="aligncenter size-full wp-image-55187">

<p>I had to go to Setting → Google → Devices → Scan for nearby devices. Only then could I add it to Find My Device.</p>

<p>The FMD service lets you share devices with another Google account. Perfect for families and loved ones! When I tried to use it, I got this error message on the GrapheneOS phone.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2024/01/not-available-fs8.png" alt="Error saying &quot;Device sharing is not available on this device&quot;." width="504" height="504" class="aligncenter size-full wp-image-55186">

<p>That's probably a GrapheneOS issue. But it is dissapointing these sorts of things aren't standardised and baked into the OS.</p>

<p>In terms of tracking - a bit crap. In Gatwick airport - a pretty busy destination - they stayed tracked for a bit after we dropped off our bags. But in less busy destinations, they never pinged the network.  They claim a 150m range which <em>ought</em> to several times better than an AirTag. But without a critical mass of Android users opted-in to the network, it is pointless.</p>

<h2 id="privacy"><a href="https://shkspr.mobi/blog/2025/01/review-pebblebee-clip-universal-and-android-find-my-device-tracker/#privacy">Privacy</a></h2>

<p>I'm a bit of a privacy nut. There's no doubt that these can be used to stalk people - but the Find My app is supposed to alert you if it detect a tag following you.</p>

<p>Is having Google and Apple know where all your stuff is a good thing? Well, probably not. But if it is a choice between seeing where a thief has taken my laptop bag and a multinational knowing what train I took, I guess I'm surprisingly OK with it.</p>

<p>Yes, it is a Devil's Bargain. Location is useful for surveillance (be it advertising or police) but it is also useful for personal security. It isn't nice living in a <a href="https://en.wikipedia.org/wiki/Panopticon">Panopticon</a> but it also isn't nice to lose your expensive possessions.</p>

<h2 id="verdict"><a href="https://shkspr.mobi/blog/2025/01/review-pebblebee-clip-universal-and-android-find-my-device-tracker/#verdict">Verdict</a></h2>

<p>From a tech point of view - they sort of work! BLE is now an established technology and is well supported on all modern phones. Google's "Find My" app is basic, but works at tracking your devices when they're near you. The device is loud, bright, and is quickly recharged.</p>

<p>If you have a phone that support it, they're a reasonable device. At £25 each, they are optimistically priced.  Especially given the coverage issues.</p>

<p>And that's the crux of the issue. As of yet, the network simply isn't as expansive as the Apple version.  Apple have the ability to push out a service to millions of users, Google don't. While there are more Android users (certainly in my part of the world) there isn't a mechanism to bootstrap this network.</p>

<p>Back in the day when Google was ambitious, they would have stuck sensors all around the country or ran a massive campaign encouraging people to get involved or launched a cool API or given out a million trackers as freebies. But Google is now a timid and cautious shadow of its former self. Everyone in tech half-expects the Find My Device network to join the <a href="https://killedbygoogle.com/">Google Graveyard</a> like so many other interesting projects.</p>

<p>So, for now, these are great if you're within a few hundred metres of them. And they're barely adequate under any other circumstances.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=54516&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/01/review-pebblebee-clip-universal-and-android-find-my-device-tracker/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		<enclosure url="https://shkspr.mobi/blog/wp-content/uploads/2024/01/pebblesmall.mp4" length="1081023" type="video/mp4" />

			</item>
		<item>
		<title><![CDATA[Should you enable TOTP *only* authentication?]]></title>
		<link>https://shkspr.mobi/blog/2024/10/should-you-enable-totp-only-authentication/</link>
					<comments>https://shkspr.mobi/blog/2024/10/should-you-enable-totp-only-authentication/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Fri, 04 Oct 2024 11:34:24 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[2fa]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[MFA]]></category>
		<category><![CDATA[totp]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=53016</guid>

					<description><![CDATA[Here&#039;s a &#34;fun&#34; thought experiment. Imagine a website which let you sign in using only your username and TOTP code.  No passwords. No magic links emailed to you. No FIDO tokens. No codes via SMS. Just a TOTP generated and displayed on your device.  Is that useful? Sensible? Practical?  It&#039;s certainly technically possible. Store the username, store the TOTP seed, done. Your users can now log in. …]]></description>
										<content:encoded><![CDATA[<p>Here's a "fun" thought experiment. Imagine a website which let you sign in using only your username and TOTP code.</p>

<p>No passwords. No magic links emailed to you. No FIDO tokens. No codes via SMS. <em>Just</em> a TOTP generated and displayed on your device.</p>

<p>Is that useful? Sensible? Practical?</p>

<p>It's certainly technically <em>possible</em>. Store the username, store the TOTP seed, done. Your users can now log in.</p>

<p>Is it <em>useful</em>? Well, it would force users to not reuse passwords they've used elsewhere. That prevents one class of security issue. If another service gets hacked, attackers can't use those credentials with your service. If you get hacked, there are no passwords stored.</p>

<p>As for <em>practical</em>? I already have 60 TOTP codes! (That's up from <a href="https://shkspr.mobi/blog/2020/08/i-have-4-2fa-coverage/">30 a few years ago</a>). Scrolling through those codes is no harder than scrolling through my password manager.</p>

<p>So, <em>sensible</em>? This all depends on your risk tolerance.</p>

<ul>
<li>A 6 digit TOTP code has a million combinations. If your service has no rate limiting, that's trivial for an attacker to brute-force.</li>
<li>An attacker <em>might</em> get lucky and score a literal one-in-a-million hit.</li>
<li>Shoulder surfing attacks are easier if the password is only 6 digits (although harder with a short time-window).</li>
</ul>

<p>Should you build an authentication mechanism like this?</p>

<p>Ehhhh… I'm going to go with "mostly no, except in limited circumstances".  It might make life slightly easier for some users.  But I feel inherently <em>icky</em> about having such a short password, even if it does regularly rotate.  If this is a low-value service without sensitive information, it <em>might</em> be useful. But for everything else, I think it is a silly ideas.</p>

<p><a href="https://mastodon.social/@Edent/113106727728186564">Further discussion on Mastodon</a>.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=53016&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2024/10/should-you-enable-totp-only-authentication/feed/</wfw:commentRss>
			<slash:comments>10</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[A decade later, has my mobile security advice changed?]]></title>
		<link>https://shkspr.mobi/blog/2024/09/a-decade-later-has-my-mobile-security-advice-changed/</link>
					<comments>https://shkspr.mobi/blog/2024/09/a-decade-later-has-my-mobile-security-advice-changed/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Mon, 30 Sep 2024 11:34:10 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[podcast]]></category>
		<category><![CDATA[security]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=52973</guid>

					<description><![CDATA[A decade ago, I appeared on the 361 Podcast to give my advice about mobile security.  This was the era of the iPhone 5 and Android KitKat. BlackBerry was trying to have (yet another) resurgence and Nokia was desperately trying to keep Windows Phone alive. What advice did I give then, and is it still relevant?    Stay Sceptical  In at number five is just stay sceptical. I mean, quite often, lots…]]></description>
										<content:encoded><![CDATA[<p>A decade ago, I appeared on the <a href="https://www.361podcast.com/s07e04">361 Podcast to give my advice about mobile security</a>.</p>

<p>This was the era of the iPhone 5 and Android KitKat. BlackBerry was trying to have (yet another) resurgence and Nokia was desperately trying to keep Windows Phone alive. What advice did I give then, and is it still relevant?</p>

<iframe src="https://player.fireside.fm/v2/NPvXvAWN+FiLUiDxm?theme=dark" width="740" height="200" frameborder="0" scrolling="no"></iframe>

<h2 id="stay-sceptical"><a href="https://shkspr.mobi/blog/2024/09/a-decade-later-has-my-mobile-security-advice-changed/#stay-sceptical">Stay Sceptical</a></h2>

<blockquote><p>In at number five is just stay sceptical. I mean, quite often, lots of mobile viruses and mobile scams spread by text message, by email, by Twitter. And these are all things that we get on our phone. But for some reason, because they seem to come from people we trust, all of our savvy just goes out the window. When you see a message from someone which purports to be your friend, just think, does this sound like them? Is what they're asking me to do a rational thing to do? And when you go and click on a link that someone has sent, check to see if it's actually taking you to where you expect to go.</p></blockquote>

<p>Still entirely relevant, sadly. You've probably received an SMS saying "Mum, I've dropped my phone. This is my temporary number." Or accidentally clicked on an advert which prompts you to hand over your credentials.</p>

<p>Scams are everywhere. One of the best things you can do to protect yourself and your data is to be less trusting.</p>

<p>Browsers are getting better at sharing real-time blocklists. So clicking on an extremely dangerous website is likely to generate a scary warning. But these technologies aren't perfect.</p>

<h2 id="dont-just-change-your-password"><a href="https://shkspr.mobi/blog/2024/09/a-decade-later-has-my-mobile-security-advice-changed/#dont-just-change-your-password">Don't <em>just</em> change your password</a></h2>

<blockquote><p>So what can I do if I have ended up putting my password into a fake site?</p>

<p>The most important thing you have to do is, if it's something like Twitter, go to settings and you'll see all the applications which have authenticated against that. You just need to go and delete all of those and then change your password.</p></blockquote>

<p>This is something that a lot of sites <em>still</em> get wrong. If a baddie has got your password, they can use OAuth to connect your account to their service. Changing your password <em>doesn't sever the link!</em></p>

<h2 id="2fa"><a href="https://shkspr.mobi/blog/2024/09/a-decade-later-has-my-mobile-security-advice-changed/#2fa">2FA</a></h2>

<blockquote><p>If you want to be really security conscious, you can turn on something called two-factor authentication. This means you give your mobile number to the social network. When you try to log in, what will happen is you type in your username and your password and then Twitter will send you a text message and it says your one-time password is 12345. You type that code in and you're logged in. That way, if someone does manage to get your username and password, it doesn't matter because they don't have your phone as well.</p></blockquote>

<p>I encouraged people to use SMS as their preferred way of enabling Multi-Factor Authentication. Back then, that was pretty much the only choice for normal people. <a href="https://www.facebook.com/notes/10157814548431886/">Facebook wouldn't introduce non-SMS MFA until 2018</a>.</p>

<p>Nowadays, I'd probably recommend using an authenticator app which generates TOTP codes.  SMS is basically fine for normal people - yes, it can be spoofed or hacked at a network level, but that's unlikely unless you're specifically targetted.</p>

<h2 id="official-app-channels"><a href="https://shkspr.mobi/blog/2024/09/a-decade-later-has-my-mobile-security-advice-changed/#official-app-channels">Official App Channels</a></h2>

<blockquote><p>Don't download apps outside of the official app store. Now, the app stores aren't perfect. You can get dodgy apps in there, but there is some safety in numbers.</p></blockquote>

<p>Reluctantly, I think I still agree with this. Back in the day, it was <em>too</em> easy to install dodgy apps. Drive-by downloads were common, and Android had a particularly poor model of security.</p>

<p>I value independent app stores like F-Droid and Aurora - but there's no doubt that they are generally for the more advanced users.  And, yeah, app stores aren't <em>perfect</em>, but they're still less likely to completely infect your phone and send premium rate messages.</p>

<h2 id="virus-checkers"><a href="https://shkspr.mobi/blog/2024/09/a-decade-later-has-my-mobile-security-advice-changed/#virus-checkers">Virus Checkers</a></h2>

<blockquote><p>you can download apps which are virus checkers of a sort. I'm quite keen on Lookout, which is a great Android app. Whenever you install something, it will check it and it will look through the list of permissions, alert you, but it will also look at the app and see whether it's been reported that it's a scam or a virus.</p></blockquote>

<p>These days, I think virus checking apps are less useful. The permissions model of Android and iOS are much improved, and it's harder for apps to do bad things in the background.</p>

<p>If you have a corporate device (or personal device with work mode) an app scanner is usually mandatory as part of your employer's Mobile Device Management policies. Again, I'm not totally convinced they're a brilliant idea. They can be useful for peace of mind, or to prevent certain classes of attacks.</p>

<h2 id="password-managers"><a href="https://shkspr.mobi/blog/2024/09/a-decade-later-has-my-mobile-security-advice-changed/#password-managers">Password Managers</a></h2>

<blockquote><p>Lots of people use really short passwords.  Why? Because they're easy to remember and they want to be able to type them into their mobile phone. And this means that people quite often have the same password for Twitter as they've got for Facebook, as they've got for email, as they've got for everything else. This is a real security nightmare because it means that if your Twitter password gets hacked, those hackers have access to everything, all your accounts. So my top tip is use a password manager.</p></blockquote>

<p>Yup! No notes. Get a password manager. I like <a href="https://bitwarden.com/">BitWarden</a> - but pick whichever meets your needs.</p>

<h2 id="physical-security"><a href="https://shkspr.mobi/blog/2024/09/a-decade-later-has-my-mobile-security-advice-changed/#physical-security">Physical Security</a></h2>

<blockquote><p>This is my number one tip for mobile security. Buy a wrist strap.</p>

<p>On your phone, you probably have a case. It's got a little hole and you can buy a lanyard, a bit of string or a bit of leather that you clip onto your phone and you wrap around your wrist while you're using it.</p>

<p>Recent reports said 10,000 phones are stolen in London every month, 120,000 a year. That's just in London. Across the UK, it's hundreds of thousands. If you're wearing a wrist strap, it is much more unlikely that someone will be able to yank the phone away from you, because if they do yank the phone away from you, chances are it's unlocked because you are making your call, you're looking at Google Maps and hey presto, they've got access to all of your email, all of your documents. They can start making premium rate phone calls straight away.</p></blockquote>

<p>I still stand by this. In London, <a href="https://www.bbc.co.uk/news/uk-england-london-65105199">a phone is stolen every 6 minutes</a> - only 2% of them are ever recovered.</p>

<p>Strap your phone to you. Don't leave it on the table when you're in a pub. If you need to check directions, turn away from the street and hold it in both hands.</p>

<p>Phones are now worth <em>thousands</em> of pounds. They are a high-value target. You probably have a banking app on your phone - or contactless payment set up. Treat your phone as though you were carrying a big wodge of notes.</p>

<p>Another part of physical security is:</p>

<blockquote><p>The other thing that you need to do is set a PIN or a password on your phone. You can use facial recognition or a thumbprint scanner.  Anything to stop a casual thief being able to get into your phone is of paramount importance.</p></blockquote>

<p>If your phone is stolen while it is unlocked, you're shit out of luck. If it's locked, it is much harder for all but the most determined attacker to get in to it. Make sure all your banking apps have passwords on them.</p>

<p>Similarly, a SIM lock is essential. You don't want someone ejecting your SIM card and making expensive calls on it.</p>

<p>I also suggested:</p>

<blockquote><p>Set up Find My Phone. If you're on Android, Android Device Manager, this means that if your phone is stolen, you can find out where it is. But much more importantly, you can click a button and have your phone be completely wiped</p></blockquote>

<p>Again, solid advice. Perhaps all that will happen is you'll <a href="https://www.bbc.co.uk/news/articles/c3rdy132q3lo">see your phone visit China</a>. But at least you'll be able to prevent the thieves getting into your data.</p>

<h2 id="vpns"><a href="https://shkspr.mobi/blog/2024/09/a-decade-later-has-my-mobile-security-advice-changed/#vpns">VPNs</a></h2>

<p>One of the hosts made this comment:</p>

<blockquote><p>If you're not familiar, a VPN is when you make a secured connection back to a server and all the data through that pipe is encrypted.
And the reason for doing that is that when I'm in a coffee shop or I'm on a public Wi-Fi network or something like that, it keeps my data secure because it doesn't matter whether the app does a good job of securing it or not. It gets it all encrypted as it goes over the network.</p></blockquote>

<p>Nowadays a VPN is less useful than it was. Let's Encrypt launched later that year and with it brought a dramatic increase in the number of Internet services which used HTTP<strong>S</strong>. The popularity of <a href="https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security">HSTS</a> increased, which means that most apps refuse to connect to non-secure versions of their site.</p>

<p>VPNs do protect you if unencrypted data is flowing through your device - but that is becoming rarer. I lean slightly towards the opinion that a VPN is <em>usually</em> a bad idea. They are, effectively, an untrusted connection between you and your destination. A malicious VPN - or one ordered to behave in such a way - is worse than no VPN.</p>

<h2 id="what-would-i-add-to-the-list"><a href="https://shkspr.mobi/blog/2024/09/a-decade-later-has-my-mobile-security-advice-changed/#what-would-i-add-to-the-list">What would I add to the list?</a></h2>

<p>I think there are a few sensible additions.</p>

<ol start="0">
<li>Back up your data. Accept that, at some point, your phone will be compromised or stolen. Ensure you have safe backups of all your stuff.

<ul>
<li>Actually <em>test</em> your backups. For most people, that means regularly look inside them to make sure all your photos are still there.</li>
</ul></li>
<li>Activate your phone's emergency features. Learn which buttons to press to automatically lock and/or disable your phone.

<ul>
<li>Practice using them. You may need to use them in an emergency.</li>
</ul></li>
<li>Make sure your Password Manager and MFA tokens can be accessed from another device.

<ul>
<li>Once your phone has gone, you will still need to get into accounts to lock them down.</li>
</ul></li>
<li>Install an ad-blocker. Not only will it protect your sanity; you're less likely to see dodgy content.

<ul>
<li>Do it on mobile <em>and</em> larger devices.</li>
</ul></li>
</ol>

<p>Stay safe out there!</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=52973&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2024/09/a-decade-later-has-my-mobile-security-advice-changed/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
			</item>
	</channel>
</rss>
