<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Fu'ad Husnan</title>
    <description>The latest articles on DEV Community by Fu'ad Husnan (@fuadhusnan_f44f3e13).</description>
    <link>https://dev.to/fuadhusnan_f44f3e13</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3914266%2F094c796a-3db7-45ac-abff-19a1b85ff8a7.png</url>
      <title>DEV Community: Fu'ad Husnan</title>
      <link>https://dev.to/fuadhusnan_f44f3e13</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fuadhusnan_f44f3e13"/>
    <language>en</language>
    <item>
      <title>Lightweight Encryption Protocols for Resource-Constrained IoT Devices</title>
      <dc:creator>Fu'ad Husnan</dc:creator>
      <pubDate>Sat, 15 Aug 2026 07:55:28 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/lightweight-encryption-protocols-for-resource-constrained-iot-devices-1k4n</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/lightweight-encryption-protocols-for-resource-constrained-iot-devices-1k4n</guid>
      <description>&lt;p&gt;Lightweight encryption protocols exist because standard cryptography assumes resources that most IoT devices don't have. A temperature sensor running on a coin cell battery cannot afford the RAM, CPU cycles, or power draw that AES-256 or RSA-2048 demand on a server. This gap between what conventional encryption needs and what embedded hardware can supply has produced an entire category of ciphers built specifically for constrained environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Standard Cryptography Fails on Small Devices
&lt;/h2&gt;

&lt;p&gt;Most encryption algorithms were designed for desktops, servers, and phones — devices with abundant memory, fast processors, and a stable power supply. IoT endpoints rarely have any of that. A typical microcontroller used in a smart lock or industrial sensor might carry 8-32 KB of RAM and run at speeds measured in single-digit megahertz, not gigahertz.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Typical constrained IoT device profile&lt;/span&gt;
&lt;span class="cp"&gt;#define RAM_AVAILABLE_KB      16
#define FLASH_AVAILABLE_KB    128
#define CPU_CLOCK_MHZ         8
#define BATTERY_CAPACITY_MAH  220
#define EXPECTED_LIFESPAN_YRS 5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under these constraints, running AES-256 in software can consume RAM the device simply doesn't have left over after handling sensor input, networking stacks, and application logic. RSA key exchange is worse — the modular exponentiation involved can take seconds on an 8-bit microcontroller, draining battery reserves that are meant to last years, not days.&lt;/p&gt;

&lt;p&gt;Engineers working on constrained hardware face a three-way trade-off: security strength, computational cost, and energy consumption. Lightweight cryptography doesn't eliminate this trade-off. It shifts the curve, offering security margins appropriate for the threat model while fitting inside a fraction of the memory and power footprint.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes a Cipher "Lightweight"
&lt;/h2&gt;

&lt;p&gt;The term lightweight cryptography refers to a specific design philosophy rather than a single algorithm. NIST formalized this category through its Lightweight Cryptography Standardization project, which ran from 2018 to 2023 and evaluated dozens of candidate algorithms against criteria including silicon area, RAM footprint, energy per bit, and resistance to side-channel attacks.&lt;/p&gt;

&lt;p&gt;Three properties distinguish lightweight ciphers from their conventional counterparts:&lt;/p&gt;

&lt;p&gt;Smaller block and key sizes reduce the memory needed to hold intermediate cryptographic state. Simplified round functions cut the number of CPU cycles required per &lt;a href="https://msf.telkomuniversity.ac.id/apa-itu-enkripsi-rahasia-di-balik-keamanan-data-digital/" rel="noopener noreferrer"&gt;encryption&lt;/a&gt; operation. Reduced code size means the compiled binary fits within the limited flash storage typical of microcontrollers, sometimes under 2 KB.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Comparing memory footprint: AES-128 vs ASCON (illustrative)&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;cipher_footprint&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ram_bytes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;rom_bytes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;cycles_per_byte&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;cipher_footprint&lt;/span&gt; &lt;span class="n"&gt;aes128&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"AES-128"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;cipher_footprint&lt;/span&gt; &lt;span class="n"&gt;ascon128&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"ASCON-128"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are representative figures rather than benchmarks from a specific chip, but they illustrate the general pattern: lightweight ciphers aim to do more with meaningfully less.&lt;/p&gt;

&lt;h2&gt;
  
  
  ASCON: The Current NIST Standard
&lt;/h2&gt;

&lt;p&gt;In February 2023, NIST selected the ASCON family as the winner of its Lightweight Cryptography competition, and in 2025 it was formally published as NIST SP 800-232. ASCON is an authenticated encryption with associated data (AEAD) construction, meaning it provides both confidentiality and integrity checking in a single pass rather than requiring separate encryption and MAC operations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;ascon.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;encrypt_sensor_reading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;plaintext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;pt_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                             &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                             &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ascon_aead_ctx_t&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ascon_aead128_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;ascon_aead128_encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;plaintext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pt_len&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;ascon_aead128_finalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ASCON's sponge-based construction is what allows it to run in such a small footprint. Unlike AES, which relies on lookup tables that consume both memory and are a known vector for cache-timing side-channel attacks, ASCON's permutation-based design avoids table lookups entirely, making it inherently more resistant to certain timing attacks on constrained hardware.&lt;/p&gt;

&lt;h2&gt;
  
  
  PRESENT and SPECK: Earlier Lightweight Approaches
&lt;/h2&gt;

&lt;p&gt;Before ASCON became the standardized answer, several other lightweight ciphers saw adoption in specific contexts. PRESENT, developed in 2007, is an ultra-lightweight block cipher designed for RFID tags and similarly constrained applications, using a 64-bit block size and either 80-bit or 128-bit keys.&lt;/p&gt;

&lt;p&gt;SPECK, published by the NSA in 2013, takes a different approach, favoring simple addition, rotation, and XOR (ARX) operations that map efficiently onto both software and hardware implementations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// SPECK round function (simplified, 32-bit words)&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;speck_round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// rotate right 8&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;^=&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// rotate left 3&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;^=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SPECK's reliance on simple arithmetic rather than substitution tables made it attractive for software-only implementations on devices without dedicated cryptographic hardware. It drew criticism, however, over its NSA origin and the absence of public design rationale for some parameter choices, which slowed formal standardization despite its practical performance advantages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Elliptic Curve Cryptography for Key Exchange
&lt;/h2&gt;

&lt;p&gt;Symmetric ciphers like ASCON and SPECK handle bulk data encryption efficiently, but IoT devices still need a way to establish shared keys in the first place. This is where the size advantage of elliptic curve cryptography (ECC) over RSA becomes significant: a 256-bit ECC key offers security roughly comparable to a 3072-bit RSA key, at a fraction of the computational cost.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ECDH key exchange using Curve25519 (via a lightweight library)&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;monocypher.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;generate_shared_secret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;my_private_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                              &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;their_public_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                              &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;shared_secret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;crypto_x25519&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shared_secret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;my_private_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;their_public_key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Curve25519 has become a common choice for constrained devices because its implementation avoids many of the timing-attack pitfalls that plague naive elliptic curve implementations, and reference code exists that compiles to just a few kilobytes of flash.&lt;/p&gt;

&lt;h2&gt;
  
  
  Protocol-Level Considerations Beyond the Cipher
&lt;/h2&gt;

&lt;p&gt;Choosing an efficient cipher solves only part of the problem. The communication protocol wrapping that cipher matters just as much for real-world deployments. DTLS (Datagram Transport Layer Security), the UDP-based counterpart to TLS, is commonly paired with CoAP (Constrained Application Protocol) in IoT deployments, but full DTLS handshakes can still be too heavy for the most constrained devices due to certificate exchange overhead.&lt;/p&gt;

&lt;p&gt;This has driven interest in pre-shared key (PSK) modes, which skip certificate-based authentication entirely in favor of keys provisioned during manufacturing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// DTLS PSK configuration example (mbedTLS)&lt;/span&gt;
&lt;span class="n"&gt;mbedtls_ssl_conf_psk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="n"&gt;psk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;psk_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;psk_identity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="n"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;psk_identity&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PSK mode trades the flexibility of certificate-based trust for a dramatically lighter handshake, which matters when a device wakes from deep sleep, needs to transmit a reading, and must return to sleep within a strict energy budget.&lt;/p&gt;

&lt;h2&gt;
  
  
  Matching Protocols to Threat Models
&lt;/h2&gt;

&lt;p&gt;Not every IoT deployment needs the same security posture. A soil moisture sensor reporting non-sensitive agricultural data has a different risk profile than a medical device transmitting patient vitals or an industrial controller managing physical machinery. Lightweight cryptography is not a shortcut around security; it's a recalibration of the trade-off between protection and resource cost for a given threat model.&lt;/p&gt;

&lt;p&gt;Devices handling sensitive data still warrant the strongest lightweight cipher available, such as ASCON-128a for higher throughput needs, combined with proper key rotation and secure boot to prevent firmware tampering. Lower-stakes telemetry devices may reasonably use a smaller security margin if it meaningfully extends battery life across a large deployed fleet, provided the failure mode of a compromise remains low-consequence.&lt;/p&gt;

&lt;p&gt;The honest limitation worth stating plainly: lightweight ciphers generally offer smaller security margins than their full-strength counterparts, and some, like SPECK, faced pushback during standardization over trust and transparency concerns. Engineers should treat cipher selection as one part of a layered security architecture, not a single point of defense, and should stay current with NIST guidance as SP 800-232 implementations mature across hardware platforms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bringing It Together
&lt;/h2&gt;

&lt;p&gt;The shift toward lightweight cryptography reflects a broader recognition that security has to fit the hardware it protects. ASCON's selection as the NIST standard gives engineers a well-vetted default for new designs, while ECC-based key exchange and PSK-mode DTLS address the handshake overhead that often gets overlooked when teams focus only on the encryption algorithm itself. For teams building constrained IoT products today, the practical starting point is ASCON for authenticated encryption, Curve25519 for key agreement, and a protocol stack — CoAP over DTLS with PSK where certificate overhead isn't justified — sized to the device's actual power and memory budget rather than borrowed wholesale from enterprise networking.&lt;/p&gt;

&lt;p&gt;Before finalizing a cryptographic approach for a new IoT product, benchmark candidate ciphers directly on your target hardware rather than relying on published figures alone, since real-world performance varies significantly across microcontroller architectures and compiler optimizations.&lt;/p&gt;

</description>
      <category>cryptography</category>
      <category>iot</category>
      <category>security</category>
    </item>
    <item>
      <title>A Secure and Efficient Image Encryption Scheme Based on Chaotic Systems</title>
      <dc:creator>Fu'ad Husnan</dc:creator>
      <pubDate>Sat, 15 Aug 2026 07:51:09 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/a-secure-and-efficient-image-encryption-scheme-based-on-chaotic-systems-4en5</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/a-secure-and-efficient-image-encryption-scheme-based-on-chaotic-systems-4en5</guid>
      <description>&lt;p&gt;Chaotic systems have become one of the most practical foundations for image encryption because they generate sequences that are deterministic yet behave unpredictably, sensitive to even tiny changes in initial conditions. This property maps directly onto what image encryption needs: pixel-level randomness that's reproducible only if you know the exact starting parameters, which effectively become the encryption key.&lt;/p&gt;

&lt;p&gt;Traditional ciphers like AES were designed for text and binary data, not images. Images have unique statistical properties — high redundancy, strong correlation between adjacent pixels, and large data volumes — that make block ciphers computationally expensive and sometimes less effective at breaking visual patterns. Chaos-based schemes address this directly by combining fast pixel scrambling (permutation) with pixel value substitution (diffusion), often outperforming conventional methods in both speed and resistance to statistical attacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Chaos Maps Well to Image Data
&lt;/h2&gt;

&lt;p&gt;A chaotic map, at its core, is a mathematical function where output values look random over time but are fully determined by an initial seed value. The logistic map is the simplest example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;logistic_map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Generate a chaotic sequence using the logistic map.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;sequence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sequence&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sequence&lt;/span&gt;

&lt;span class="c1"&gt;# r=3.99 sits in the chaotic regime; x0 is the secret seed
&lt;/span&gt;&lt;span class="n"&gt;chaotic_seq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;logistic_map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x0&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.6152&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;3.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chaotic_seq&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change &lt;code&gt;x0&lt;/code&gt; by even 0.0000001 and the resulting sequence diverges completely within a handful of iterations. That sensitivity to initial conditions — known as the butterfly effect — is what makes chaotic sequences useful as pseudo-random number generators for cryptographic purposes. The seed values (x0, r, and any additional parameters) become the encryption key, and without them, reconstructing the sequence is computationally infeasible.&lt;/p&gt;

&lt;p&gt;Single logistic maps are easy to implement but have a known weakness: their chaotic range is narrow, and weak keys can produce periodic, predictable output. This is why most modern schemes chain multiple maps together, or use higher-dimensional systems like the Chen system, Lorenz attractor, or hyperchaotic maps, to widen the effective key space and eliminate periodic windows.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Permutation-Diffusion Architecture
&lt;/h2&gt;

&lt;p&gt;Most chaos-based image encryption schemes follow a two-stage structure: permutation, which scrambles pixel positions, followed by diffusion, which alters pixel values based on their neighbors. Neither stage alone is secure. Permutation preserves the histogram (an attacker can still see the same distribution of pixel values, just rearranged), while diffusion alone doesn't break spatial correlation between adjacent pixels. Combined, they address both weaknesses.&lt;/p&gt;

&lt;p&gt;Here's a simplified implementation showing both stages using NumPy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_chaotic_sequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zeros&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;permute_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chaotic_seq&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Stage 1: scramble pixel positions using sorted chaotic indices.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;flat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;indices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;argsort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chaotic_seq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;permuted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;indices&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;permuted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reshape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;diffuse_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chaotic_seq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key_stream_scale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Stage 2: XOR each pixel with a chaos-derived keystream, chained sequentially.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;flat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;keystream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chaotic_seq&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;key_stream_scale&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cipher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zeros_like&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flat&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="n"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="n"&gt;keystream&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt;
        &lt;span class="n"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reshape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;encrypt_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x0&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.6152&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;3.99&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;total_pixels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;
    &lt;span class="n"&gt;chaotic_seq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_chaotic_sequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total_pixels&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;permuted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;permute_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chaotic_seq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;encrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;diffuse_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;permuted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chaotic_seq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;encrypted&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;prev&lt;/code&gt; variable in &lt;code&gt;diffuse_image&lt;/code&gt; is what creates the diffusion effect: each ciphered pixel depends on the plaintext pixel, the keystream, and the previous ciphertext value. A single-pixel change anywhere in the plaintext propagates forward through the rest of the encrypted image, which is exactly what defeats differential attacks — an adversary comparing two slightly different plaintext images and their ciphertexts should see the changes spread unpredictably, not stay localized.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measuring Whether the Scheme Actually Works
&lt;/h2&gt;

&lt;p&gt;Encryption schemes for images are evaluated with a specific set of statistical tests, distinct from those used for text encryption, because the goal is to confirm that the output has no visually or statistically exploitable structure left over from the original.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Histogram uniformity&lt;/strong&gt; checks whether pixel intensity values are evenly distributed after encryption. A plaintext image typically has a histogram with visible peaks and patterns (skies cluster around certain blue values, skin tones cluster together). A well-encrypted image should have a flat, uniform histogram, meaning every pixel value from 0–255 appears roughly the same number of times.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Correlation coefficient analysis&lt;/strong&gt; measures how strongly adjacent pixels relate to each other, horizontally, vertically, and diagonally. Natural images have correlation coefficients close to 1 (neighboring pixels are nearly identical). Effective &lt;a href="https://repository.telkomuniversity.ac.id/pustaka/94472/analisis-dan-implementasi-identity-based-encryption-boneh-franklin.html" rel="noopener noreferrer"&gt;encryption&lt;/a&gt; should push this close to 0.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;correlation_coefficient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;horizontal&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;direction&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;horizontal&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:].&lt;/span&gt;&lt;span class="nf"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;direction&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;vertical&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;:].&lt;/span&gt;&lt;span class="nf"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="p"&gt;:].&lt;/span&gt;&lt;span class="nf"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:].&lt;/span&gt;&lt;span class="nf"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cov&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cov&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;std&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;std&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NPCR and UACI&lt;/strong&gt; (Number of Pixels Change Rate and Unified Average Changing Intensity) quantify sensitivity to plaintext changes. NPCR measures the percentage of pixels that differ between two ciphertexts produced from images that differ by just one pixel; values close to 99.6% are typically considered strong. UACI measures the average intensity difference between those two ciphertexts, with values near 33.4% considered ideal for 8-bit images. Schemes that fall noticeably below these benchmarks are more vulnerable to differential cryptanalysis.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key space and key sensitivity&lt;/strong&gt; matter just as much as the statistical tests. A key space smaller than 2^100 is generally considered insufficient against brute-force attacks with modern computing resources. Key sensitivity testing confirms that decrypting with a key different from the original by even a single bit produces a completely unrelated, still-encrypted-looking output rather than a slightly distorted version of the original image.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Chaos-Based Schemes Fall Short
&lt;/h2&gt;

&lt;p&gt;It's worth being direct about the trade-offs, since a lot of published schemes oversell their security. Floating-point chaotic maps implemented in software can suffer from dynamical degradation: because computers use finite-precision arithmetic, a chaotic sequence that should never repeat can fall into short periodic cycles after enough iterations. This is a real, documented weakness, not a theoretical one, and it's the reason some peer-reviewed schemes have later been broken by researchers who found the effective key space was far smaller than claimed.&lt;/p&gt;

&lt;p&gt;Performance is another trade-off. While chaos-based schemes are generally faster than applying full AES-256 to large images, they're still slower than specialized hardware ciphers when there's no dedicated silicon support, and many academic implementations don't account for real-world constraints like encrypting video streams in real time or running on resource-constrained IoT camera modules.&lt;/p&gt;

&lt;p&gt;There's also a gap between passing statistical tests and having formal security proofs. NPCR, UACI, and histogram tests are necessary but not sufficient. A scheme can pass every standard statistical benchmark and still be vulnerable to chosen-plaintext attacks if the permutation and diffusion stages aren't properly coupled to the plaintext itself, which is why more recent designs make the initial chaotic seed a function of the plaintext (often via a hash like SHA-256 of the image), rather than a fixed key reused across every image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;derive_seed_from_plaintext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base_key&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Bind the chaotic seed to the plaintext to resist chosen-plaintext attacks.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;image_bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tobytes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;combined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;image_bytes&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;base_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;digest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;combined&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;seed_fraction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mh"&gt;0xFFFFFFFF&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;seed_fraction&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Practical Recommendations
&lt;/h2&gt;

&lt;p&gt;For anyone implementing or evaluating a chaos-based image encryption scheme, a few design choices consistently separate resilient implementations from fragile ones. Using higher-dimensional or hyperchaotic systems instead of a single logistic map meaningfully widens the key space and avoids the narrow chaotic windows that plague simpler maps. Binding the seed to the plaintext, as shown above, closes off a whole category of chosen-plaintext attacks that fixed-key schemes remain exposed to. And running the full battery of tests — histogram, correlation, NPCR/UACI, and key sensitivity — rather than cherry-picking the ones that look favorable, gives a much more honest picture of where a scheme actually stands.&lt;/p&gt;

&lt;p&gt;None of this makes chaos-based encryption a drop-in replacement for standardized, formally analyzed ciphers in every context. For applications with strict compliance requirements, AES with a properly randomized IV remains the safer default. But for scenarios where image-specific performance matters, such as real-time video encryption, embedded camera systems, or medical imaging pipelines with large file volumes, a well-constructed chaos-based scheme, particularly one that layers permutation, plaintext-bound diffusion, and a wide-range chaotic generator, offers a genuinely competitive balance of speed and security.&lt;/p&gt;

&lt;p&gt;If you're building or evaluating one of these systems, start with the statistical test suite before optimizing for speed. A fast scheme that fails NPCR or leaves correlation coefficients above 0.1 isn't saving you anything; it's just moving the vulnerability from computation time to attack surface.&lt;/p&gt;

</description>
      <category>encryption</category>
      <category>security</category>
    </item>
    <item>
      <title>Why Cloud Storage Needs More Than Just a Password</title>
      <dc:creator>Fu'ad Husnan</dc:creator>
      <pubDate>Sat, 15 Aug 2026 07:46:48 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/why-cloud-storage-needs-more-than-just-a-password-3hgh</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/why-cloud-storage-needs-more-than-just-a-password-3hgh</guid>
      <description>&lt;p&gt;Cloud storage security can no longer rely on a password as its main line of defense. Attackers have shifted their focus from breaking encryption to simply logging in, and they are succeeding at a scale that should worry anyone storing sensitive data in the cloud. Identity-based attacks now account for the majority of cloud breaches, which means the weakest point in most storage systems isn't the infrastructure. It's the login screen.&lt;/p&gt;

&lt;p&gt;This shift matters because cloud storage is fundamentally different from an on-premises file server. In a traditional setup, an attacker needs network access before they can even attempt to steal data. In the cloud, identity &lt;em&gt;is&lt;/em&gt; the access. A single set of valid credentials can open the door to databases, storage buckets, and backups across an entire environment, no network breach required.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Password-Only Model Was Never Designed for This
&lt;/h2&gt;

&lt;p&gt;Passwords were built for a world where the biggest threat was someone guessing a weak word scrawled on a sticky note. That threat still exists, but it's now a minor concern compared to industrialized credential theft. Criminal groups sell subscription-style access to freshly stolen login data, and stolen credential logs circulate on forums by the millions. Verizon's 2025 Data Breach Investigations Report found stolen credentials served as the initial access vector in roughly 22% of confirmed breaches, and reused or duplicated passwords showed up in the vast majority of a 19-billion-password leak dataset analyzed by researchers.&lt;/p&gt;

&lt;p&gt;None of this requires a sophisticated attacker. If a password has been reused anywhere else on the internet, and that other service has been breached, the credential is already circulating. Automated tools test these combinations against cloud storage login pages around the clock. This is the mechanism behind most cloud storage compromises: not clever hacking, but patient, automated credential stuffing against a system that trusted a single factor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Misconfiguration Is the Silent Partner in Most Breaches
&lt;/h2&gt;

&lt;p&gt;Weak credentials rarely act alone. They tend to pair with configuration mistakes that turn a single compromised login into a full-scale exposure. Publicly accessible storage buckets, overly permissive access roles, and unencrypted volumes are among the most common misconfigurations security researchers flag every year, and each one multiplies the damage a stolen password can do.&lt;/p&gt;

&lt;p&gt;Consider how this plays out in practice. An engineer sets up a storage bucket during a sprint, intending to lock down permissions "later." The bucket goes live with public read access because that was the fastest way to get a demo working. Weeks pass. Nobody circles back. Now anyone with the URL, or anyone running an automated scanner for exposed buckets, can browse the contents without ever touching a login form. Analysts researching cloud security have consistently found that a meaningful share of organizations have at least one public-facing storage bucket containing sensitive data, and that human error, not sophisticated attack tooling, is the dominant root cause behind cloud security failures.&lt;/p&gt;

&lt;p&gt;This is why security teams describe cloud protection as a shared responsibility model. The cloud provider secures the physical infrastructure, the hypervisors, and the network backbone. Everything layered on top of that, including who can access which bucket and under what conditions, is the customer's job. A strong password on an account doesn't help if the bucket itself is set to public.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Closes the Gap
&lt;/h2&gt;

&lt;p&gt;Multi-factor authentication is the most direct fix for credential-based attacks, and it's also the cheapest to implement relative to the risk it removes. Requiring a second verification step means a stolen password alone can no longer grant access. Attackers can and do work around weak forms of MFA, particularly SMS-based codes vulnerable to SIM swapping, but app-based authenticators and hardware security keys raise the cost of an attack significantly.&lt;/p&gt;

&lt;p&gt;Passkeys are becoming the more durable long-term answer. Unlike a password, a passkey is a cryptographic key pair, tied to the device that generated it, that can't be phished or reused across services the way a typed password can. Adoption has moved quickly. According to the FIDO Alliance, more than a billion people have activated at least one passkey, and nearly half of the world's top 100 websites now support them. Cloud storage providers that support passkey login give users a way to sidestep the password-reuse problem entirely, rather than trying to patch around it.&lt;/p&gt;

&lt;p&gt;Least-privilege access is the second pillar. Every account, service, and API key should have exactly the permissions it needs to function, and nothing more. This limits what a compromised credential can actually do. A marketing intern's login shouldn't be able to touch financial records, and a backend service account shouldn't have delete permissions across every bucket in the environment just because it was easier to configure that way during setup.&lt;/p&gt;

&lt;p&gt;Here's a simplified example of tightening an access policy on a cloud storage bucket, moving from an overly broad grant to something closer to least privilege:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-01-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Deny"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::company-reports/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Bool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"aws:MultiFactorAuthPresent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"false"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"AWS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::123456789012:role/ReportsReadOnly"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:ListBucket"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::company-reports"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::company-reports/*"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This policy does two things a password-only setup can't. It denies any action on the bucket unless MFA was present at the time of the request, and it scopes access to a specific role limited to read-only operations. Even if a credential tied to that role leaked, the blast radius is contained to reading report files, not deleting or modifying them, and MFA still stands between the attacker and the data.&lt;/p&gt;

&lt;p&gt;Encryption at rest and in transit is the third layer, and it should be treated as a default rather than an optional setting. Storage providers generally offer this out of the box, but it's worth verifying rather than assuming, particularly for backup copies and secondary regions where settings can drift from the primary configuration. Unencrypted secrets sitting in code repositories or configuration files are a recurring finding in security audits, and they undermine &lt;a href="https://bse-sby.telkomuniversity.ac.id/rsa-aes-dan-sha-256-pilar-keamanan-data-di-dunia-digital-2020-2025/" rel="noopener noreferrer"&gt;encryption&lt;/a&gt; efforts elsewhere in the stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring Closes the Loop
&lt;/h2&gt;

&lt;p&gt;Prevention measures reduce the odds of a breach, but they don't eliminate it. Detection is what limits how much damage a breach causes once it happens. Breaches that go unnoticed for months are common in cloud environments, and the ones spanning multiple cloud environments tend to take the longest to identify and contain.&lt;/p&gt;

&lt;p&gt;Logging access to storage buckets, alerting on unusual download volumes, and reviewing permission changes on a regular cadence are unglamorous practices compared to picking a fancier authentication method, but they're what turns a breach from a months-long undetected leak into an incident caught within hours. A storage bucket that suddenly has thousands of objects downloaded overnight by a service account that normally sits idle is a signal worth acting on immediately, not something to notice in a quarterly review.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Realistic Security Baseline
&lt;/h2&gt;

&lt;p&gt;None of this requires an enterprise security budget to get started. A reasonable baseline looks like enforcing MFA or passkeys across every account with storage access, auditing bucket and folder permissions for public exposure at least quarterly, applying least-privilege roles to service accounts and API keys, confirming encryption is active on all storage tiers including backups, and turning on access logging with alerts for anomalous activity.&lt;/p&gt;

&lt;p&gt;The honest trade-off is friction. MFA adds a step to every login. Least-privilege access means more upfront work defining roles instead of granting broad permissions and moving on. Regular audits take time away from other priorities. None of these measures are free, and organizations that skip them aren't necessarily being reckless; they're often just prioritizing speed under real constraints. But the cost comparison isn't close. A compromised-credential breach now averages well over four million dollars according to IBM's Cost of a Data Breach Report, with an average detection and containment window stretching past 200 days. The friction of MFA is measured in seconds. The friction of a breach is measured in months and millions.&lt;/p&gt;

&lt;p&gt;Passwords aren't going away, and they don't need to. What needs to change is treating them as one layer in a system rather than the whole system. Cloud storage that pairs a password with strong MFA, scoped permissions, active encryption, and real monitoring is a fundamentally different security posture than a bucket protected by a single login field. If your current setup can be summed up as "there's a password on it," that's the gap worth closing first.&lt;/p&gt;

&lt;p&gt;If you're evaluating your own cloud storage setup, start with an honest audit: check for public bucket exposure, confirm MFA is enforced everywhere, and verify that no service account has more access than its job requires. Those three checks alone catch the majority of what turns a stolen password into a full breach.&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Breaking Down the Shield: Common Misconceptions About Data Privacy</title>
      <dc:creator>Fu'ad Husnan</dc:creator>
      <pubDate>Sat, 15 Aug 2026 07:45:13 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/breaking-down-the-shield-common-misconceptions-about-data-privacy-3o1k</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/breaking-down-the-shield-common-misconceptions-about-data-privacy-3o1k</guid>
      <description>&lt;p&gt;Data privacy is one of those topics everyone has an opinion on, but few people fully understand, and that gap is exactly where bad decisions get made. Most people assume they are either fully protected by the law or fully exposed with nothing to be done about it, and both extremes are wrong. The reality sits in the messy middle, shaped by consent mechanics, anonymization limits, and enforcement patterns that rarely make headlines until a company gets fined.&lt;/p&gt;

&lt;p&gt;This matters more in 2026 than it did even two years ago. &lt;cite&gt;Data privacy risk is reaching a critical mass as "zombie" privacy claims, tougher state laws, and everyday AI use converge to create significant liability for companies.&lt;/cite&gt; The misconceptions that used to be harmless dinner-table opinions are now the same misconceptions showing up in regulatory enforcement actions and class-action filings. Below are the ones worth correcting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Misconception 1: "I Have Nothing to Hide, So Privacy Doesn't Matter to Me"
&lt;/h2&gt;

&lt;p&gt;This is the most common objection to caring about data privacy at all, and it rests on a narrow definition of harm. The nothing-to-hide argument assumes privacy only protects wrongdoing, so if you have done nothing wrong, there is nothing to protect. Legal scholar Daniel Solove has spent years dismantling this framing, arguing that &lt;cite&gt;the nothing-to-hide argument holds that there is no threat to privacy unless authorities uncover unlawful activity, and it is one of the most prevalent yet flawed justifications for dismissing privacy concerns.&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;The flaw becomes obvious once you look at what companies actually do with behavioral data that has nothing incriminating in it. Purchase history, browsing patterns, location trails, and app usage get combined to build predictive profiles used for targeting, pricing, and persuasion, none of which requires you to have done anything wrong. The Cambridge Analytica scandal remains the clearest public example: &lt;cite&gt;behavioral data extracted from ordinary, legal activity was used to predict and influence people's decisions, even though nothing incriminating existed in their digital activity.&lt;/cite&gt; Secrecy was never the issue. The existence of a detailed, tradeable profile of your behavior is the issue, regardless of what that behavior contains.&lt;/p&gt;

&lt;p&gt;Post-scandal reforms addressed consent and disclosure, not the underlying profiling. Regulations like GDPR and CCPA require companies to ask permission and be transparent about data use, but they generally don't prohibit building predictive profiles once permission is technically granted. That gap is worth understanding before assuming "nothing to hide" settles the question.&lt;/p&gt;

&lt;h2&gt;
  
  
  Misconception 2: Cookie Banners Are the Law, and Rejecting Them Is Optional
&lt;/h2&gt;

&lt;p&gt;Most internet users interact with a cookie consent banner daily and assume it exists because some regulation specifically mandates a banner. That's backwards. &lt;cite&gt;The GDPR does not actually require websites to use cookie banners; instead, it requires companies to obtain explicit consent before tracking a person's online movements, and the banner is simply the mechanism the industry adopted to collect that consent.&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;This distinction matters because it explains why so many cookie banners are designed to be confusing or annoying rather than genuinely optional. A banner with a prominent "Accept All" button and a buried, multi-click path to "Reject All" is technically a consent mechanism, but it is not the kind of clear, freely given consent the underlying law actually demands. Regulators have started noticing. &lt;cite&gt;The UK's Information Commissioner's Office has expanded its enforcement to the top 1,000 websites, with common findings including cookies dropped before consent is given and the absence of a visible "Reject All" option.&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;There's a second, related misconception buried in here: that once a consent banner is implemented correctly, the job is done. &lt;cite&gt;The biggest misconception in consent management is treating implementation as a "set it and forget it" task, when in reality marketing tags change, new tracking pixels get deployed, and scripts evolve, creating compliance gaps over time.&lt;/cite&gt; A banner that was compliant at launch can quietly become non-compliant six months later without anyone touching the consent code itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Misconception 3: Anonymized Data Can't Be Traced Back to You
&lt;/h2&gt;

&lt;p&gt;Companies routinely promise that shared or sold data has been "anonymized," and that word does a lot of reassurance work it may not have earned. Anonymization typically means stripping out obvious identifiers like names, Social Security numbers, and addresses, but obvious identifiers are not the only path back to a person. &lt;cite&gt;Even data that has gone through de-identification, with direct identifiers masked or removed, can often be re-identified by matching it against publicly available auxiliary information using basic computer science techniques.&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;This isn't theoretical. Researchers have repeatedly shown that combining a handful of supposedly harmless attributes, such as birth date, zip code, and gender, can uniquely identify a large share of a population even without a name attached. &lt;cite&gt;Datasets stripped of explicitly identifying information are not immune to privacy risks, because there may still be enough information in an "anonymized" dataset to reveal the identity of specific individuals.&lt;/cite&gt; The technique is called re-identification, and it doesn't require sophisticated hacking, just enough auxiliary data points to narrow the field down to one person.&lt;/p&gt;

&lt;p&gt;Some organizations use more rigorous statistical techniques to reduce this risk. Differential privacy adds mathematical noise designed to preserve aggregate patterns while protecting individuals, and it can retain a large share of correlation accuracy in analytics use cases. But differential privacy is a deliberate engineering choice, not the default outcome of simply removing a name field from a spreadsheet, and plenty of "anonymized" datasets in circulation never received that level of treatment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Misconception 4: Privacy Laws Only Apply to Big Tech Companies
&lt;/h2&gt;

&lt;p&gt;Small and mid-sized businesses often assume privacy regulation is a large-enterprise problem, something for companies with the scale of a major platform to worry about. That assumption is increasingly costly. Beyond the newer, well-known frameworks, older statutes are being repurposed against ordinary businesses. &lt;cite&gt;So-called "zombie" laws that predate modern statutes remain among the biggest privacy threats today, and while only government agencies can enforce newer laws, these older laws open the door to class-action lawsuits and fixed, per-person fines regardless of company size.&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;Enforcement data backs this up. &lt;cite&gt;Analytics-specific breaches accounted for 68% of 2026 enforcement actions, driven largely by machine learning training on non-consented data and re-identification risks&lt;/cite&gt;, and the businesses affected span far beyond the household-name platforms typically associated with privacy scandals. A local retailer running a customer analytics dashboard, a regional healthcare provider, or a mid-sized SaaS company handling user data can all trigger the same categories of liability as a large tech firm, often with fewer resources to defend against it.&lt;/p&gt;

&lt;p&gt;The financial exposure compounds quickly once a claim is filed. &lt;cite&gt;Remediation costs, legal fees, and stock or reputational impact from a privacy violation commonly scale into the multi-million-dollar range per incident, well above whatever the regulatory penalty alone would have been.&lt;/cite&gt; Smaller organizations without dedicated legal or compliance teams are frequently the least prepared for that kind of exposure, not the most protected from it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Misconception 5: AI Tools Are Covered by the Same Confidentiality Rules as Everything Else
&lt;/h2&gt;

&lt;p&gt;As AI tools have become standard software in many workplaces, a specific and consequential misconception has followed them: that a vendor's promise not to train on your data is equivalent to a confidentiality guarantee. It isn't. &lt;cite&gt;An AI tool's contractual commitment not to train on a company's data is not the same as a confidentiality obligation, and most businesses are sending sensitive and proprietary input to a destination that is effectively unknown.&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;The risk isn't limited to officially sanctioned tools, either. Employees frequently turn to personal or unlicensed AI tools to solve problems faster, creating exposure that company leadership isn't even aware exists. &lt;cite&gt;Employees using unlicensed or personal AI tools to meet their needs can create risks a company doesn't know about, and this becomes particularly risky when the activity involves product development or discussions of legal and compliance issues.&lt;/cite&gt; Conversations that would normally be protected by attorney-client privilege or internal confidentiality policies lose that protection the moment they're typed into a general-purpose AI chat interface, because those conversations and usage records are typically discoverable in litigation.&lt;/p&gt;

&lt;p&gt;Hosted models running in a dedicated, contractually isolated cloud environment can reduce this specific risk, since the data doesn't leave a controlled boundary. But that requires a deliberate infrastructure decision, not just trust in a vendor's terms of service. Most default consumer-facing AI tools were not built with that boundary in mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Misconception 6: Incognito Mode Makes You Invisible Online
&lt;/h2&gt;

&lt;p&gt;This one persists because the name itself implies total concealment, and the reality is much narrower. &lt;cite&gt;The misconception is that opening an incognito or private browsing window means no one can track what you do, but incognito mode only hides your activity from other people who use the same device.&lt;/cite&gt; Your internet service provider, the websites you visit, and any advertising network embedded on those sites can still see and log your activity during a private browsing session.&lt;/p&gt;

&lt;p&gt;This misunderstanding often travels alongside a second one: that &lt;a href="https://bit-sby.telkomuniversity.ac.id/enkripsi-di-dunia-nyata-dari-whatsapp-hingga-blockchain/" rel="noopener noreferrer"&gt;encryption&lt;/a&gt; and private storage tools are only necessary for people with something to actively conceal. &lt;cite&gt;The misconception here is that only people doing something shady need encryption or private storage, when in practice these tools protect ordinary financial records, health information, and personal communications from exposure in a breach.&lt;/cite&gt; Treating privacy tools as a signal of suspicious behavior, rather than as a baseline hygiene practice, leaves a lot of ordinary, sensitive information more exposed than it needs to be.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why These Misconceptions Persist
&lt;/h2&gt;

&lt;p&gt;Part of the reason these ideas stick around is that privacy policies are written to be technically accurate while remaining functionally unhelpful. A privacy policy can disclose exactly what a company does with your data in language few people will read closely enough to understand the implications. This is why privacy-focused organizations increasingly advise looking past the policy itself. &lt;cite&gt;Focusing solely on the privacy policies and marketing of a tool or provider can blind you to its actual weaknesses; the better approach is determining what the underlying technical problem is and confirming a real technical solution addresses it, rather than assuming a "privacy-focused" label alone solves anything.&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;That framing applies well beyond individual tool choices. Whether the question is a cookie banner, an anonymized dataset, or an AI vendor's contract terms, the useful move is the same: identify the specific technical or legal guarantee being claimed, and verify it rather than accepting the label at face value.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Means in Practice
&lt;/h2&gt;

&lt;p&gt;None of this requires becoming a privacy lawyer to act on. For individuals, the practical takeaways are straightforward: treat "anonymized" as a claim to verify rather than a guarantee, understand that incognito mode is a local-device feature and not a network-level shield, and be deliberate about which AI tools see sensitive personal or professional information.&lt;/p&gt;

&lt;p&gt;For businesses, the stakes are higher and the misconceptions more expensive. Company size is not a reliable predictor of legal exposure, consent mechanisms need ongoing maintenance rather than a one-time setup, and AI tool adoption needs a policy that accounts for what employees are actually doing, not just what's officially sanctioned. Given how much enforcement activity is now targeting analytics practices and consent gaps specifically, a periodic audit of what data is collected, how it's anonymized or secured, and which AI tools are touching it is no longer optional due diligence. It's a basic cost of doing business in a regulatory environment that is only getting more active from here.&lt;/p&gt;

</description>
      <category>privacy</category>
      <category>data</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Why Cloud Storage Needs More Than Just a Password</title>
      <dc:creator>Fu'ad Husnan</dc:creator>
      <pubDate>Sat, 15 Aug 2026 07:40:34 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/why-cloud-storage-needs-more-than-just-a-password-119h</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/why-cloud-storage-needs-more-than-just-a-password-119h</guid>
      <description>&lt;p&gt;Cloud storage security still gets treated as a login problem, but the numbers say otherwise. Compromised identities now account for over 70% of cloud breaches, and human error drives 88% of all data breach incidents overall. A password, no matter how long or how often it's rotated, is a single point of failure sitting in front of an ever-expanding attack surface. If that one credential falls, everything behind it is exposed.&lt;/p&gt;

&lt;p&gt;This gap matters more now than it did five years ago. Storage buckets, shared drives, and backup systems hold the operational core of most businesses: financial records, source code, customer data, internal communications. Attackers know this, and they've adjusted their methods accordingly. Credential theft, phishing, and session hijacking are cheaper and more reliable than exploiting a zero-day vulnerability, so that's where the effort goes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Password Was Never Meant to Carry This Much Weight
&lt;/h2&gt;

&lt;p&gt;Passwords were designed for a simpler threat model: one person, one device, one login screen. They work reasonably well against random guessing. They work poorly against phishing kits that clone login pages in minutes, credential-stuffing bots that test billions of leaked username-password pairs, and infostealer malware that lifts saved credentials directly from a browser.&lt;/p&gt;

&lt;p&gt;Once a password is compromised, an attacker doesn't need to "hack" anything else. They log in like a normal user. Most cloud storage platforms don't flag that kind of access as suspicious, because technically, it isn't — the correct credentials were used. This is why phishing remains the most prevalent breach vector, affecting roughly 73% of organizations, and why identity-based attacks are outpacing infrastructure exploits year over year.&lt;/p&gt;

&lt;p&gt;The practical result is that a strong password policy alone gives a false sense of security. It raises the bar for guessing attacks while leaving the door open for theft, reuse, and social engineering — the methods attackers actually favor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-Factor Authentication Closes the Most Common Gap
&lt;/h2&gt;

&lt;p&gt;Multi-factor authentication (MFA) doesn't eliminate credential theft, but it breaks the chain that turns stolen credentials into account access. A phished password is far less useful to an attacker if it can't be paired with a second verification step tied to a device or app the attacker doesn't control.&lt;/p&gt;

&lt;p&gt;Setting this up doesn't require custom development in most cases — cloud storage providers expose it directly through their admin or account settings. For platforms that support programmatic enforcement, a basic policy check might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;enforce_mfa_policy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_account&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Checks whether a user account meets minimum authentication
    requirements before granting storage access.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;user_account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mfa_enabled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;PermissionError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Access denied: MFA not enabled for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_account&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user_account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mfa_method&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app_totp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hardware_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;PermissionError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Access denied: unsupported MFA method for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_account&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SMS-based codes are better than nothing, but they remain vulnerable to SIM-swapping attacks. App-based authenticators (TOTP) and hardware security keys are meaningfully stronger, and hardware keys in particular are close to phishing-proof, since the authentication is bound to the physical device and the specific domain being accessed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encryption Needs to Cover Data at Rest and in Transit — Consistently
&lt;/h2&gt;

&lt;p&gt;Encryption is often assumed to be handled automatically by the cloud provider, and in many cases the baseline is. The gap shows up in the inconsistency: data might be encrypted in the primary storage environment but left unencrypted in a backup copy, a staging environment, or a third-party integration that syncs the same files elsewhere. Fragmented encryption coverage across multi-cloud and hybrid setups is a recurring theme in breach analysis, and it's rarely intentional — it's usually the result of teams adding new tools and storage locations faster than they update their encryption standards to match.&lt;/p&gt;

&lt;p&gt;A basic encryption-at-rest example, using a standard library rather than a custom implementation, illustrates the principle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;cryptography.fernet&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Fernet&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;encrypt_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;fernet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Fernet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;original_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;encrypted_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fernet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;original_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_path&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.enc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;encrypted_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;encrypted_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encrypted_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Generate and store this key securely — never hardcode it
&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Fernet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_key&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;encrypt_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;financial_report.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code itself is straightforward. The harder part is governance: knowing where every copy of sensitive data lives, confirming &lt;a href="https://it.telkomuniversity.ac.id/kriptografi-adalah/" rel="noopener noreferrer"&gt;encryption&lt;/a&gt; is applied consistently across all of them, and managing the encryption keys separately from the data they protect. A key stored next to the encrypted file defeats the purpose of encrypting it in the first place.&lt;/p&gt;

&lt;p&gt;For data in transit, TLS should be non-negotiable for any connection to cloud storage — API calls, sync clients, and browser sessions alike. Most providers enforce this by default, but custom integrations and older client libraries sometimes fall back to unencrypted connections silently, which is worth auditing directly rather than assuming.&lt;/p&gt;

&lt;h2&gt;
  
  
  Access Controls Should Assume Compromise, Not Prevent It
&lt;/h2&gt;

&lt;p&gt;Zero-trust architecture has moved from buzzword to default recommendation for a specific reason: it assumes that any credential, device, or session could already be compromised, and designs access accordingly. Instead of granting broad access once a user authenticates, zero-trust models re-verify continuously and limit what any single account can reach.&lt;/p&gt;

&lt;p&gt;In practice, this means applying the principle of least privilege to cloud storage permissions. A marketing team member doesn't need write access to financial records. A read-only integration doesn't need delete permissions. Overly permissive IAM roles, particularly ones using wildcard permissions, remain one of the most common misconfigurations found in cloud security audits, and they're also one of the easiest to fix once identified.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Overly permissive - avoid
&lt;/span&gt;&lt;span class="n"&gt;policy_broad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Effect&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Action&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;s3:*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Resource&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Scoped to what the role actually needs
&lt;/span&gt;&lt;span class="n"&gt;policy_scoped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Effect&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Action&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;s3:GetObject&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;s3:ListBucket&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Resource&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arn:aws:s3:::reports-bucket/*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second policy limits blast radius. If the credentials tied to that role are ever compromised, the damage is contained to read access on one bucket, not full control over every storage resource in the account.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring and Audit Trails Turn Detection From Guesswork Into a Process
&lt;/h2&gt;

&lt;p&gt;Even well-configured storage systems get breached. What separates a contained incident from a prolonged one is usually detection speed. Breaches spanning multiple cloud environments take an average of 276 days to identify and contain — a window long enough for attackers to move laterally, establish persistence, and extract data gradually enough to avoid triggering obvious alarms.&lt;/p&gt;

&lt;p&gt;Audit logging closes part of that gap, but only if someone is actually reviewing the logs or alerting on anomalies within them. A missing or unreviewed audit trail is itself a contributing factor in a meaningful share of cloud security incidents. Basic anomaly detection doesn't require a dedicated security team to start:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;flag_unusual_access&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;access_log&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;baseline_hours&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Flags storage access events outside typical business hours
    or from unrecognized locations.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;flagged&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;access_log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;hour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hour&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;baseline_hours&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;hour&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;baseline_hours&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="n"&gt;flagged&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;location&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;known_locations&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt;
            &lt;span class="n"&gt;flagged&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;flagged&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This kind of check won't catch a sophisticated attacker who mimics normal behavior, but it catches a large share of automated and opportunistic access attempts, which still make up most incidents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backups Are a Target, Not Just a Safety Net
&lt;/h2&gt;

&lt;p&gt;Backup systems used to be treated as the recovery plan for when something else went wrong. Attackers have caught up to that assumption, and now target cloud backups directly, since compromising a backup can undermine the recovery process itself — encrypting or deleting backups alongside primary data is a standard step in modern ransomware operations.&lt;/p&gt;

&lt;p&gt;The fix isn't complicated in concept: backups need the same access controls, encryption, and monitoring as primary storage, plus one addition — immutability. A backup that can be modified or deleted by the same credentials that access daily operational data offers limited protection against a ransomware scenario. Write-once, read-many (WORM) storage configurations or versioned backups with delayed deletion policies address this directly, giving teams a recovery point that an attacker with valid credentials still can't erase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Realistic Security Layer
&lt;/h2&gt;

&lt;p&gt;None of these measures function well in isolation. MFA without least-privilege access controls still leaves an over-permissioned account as a high-value target. Encryption without key management discipline just moves the vulnerability from the data to the key. Monitoring without a response process generates alerts nobody acts on.&lt;/p&gt;

&lt;p&gt;The organizations with the strongest cloud storage security aren't necessarily the ones spending the most — they're the ones treating security as layered and ongoing rather than a checklist completed once at setup. Given that Gartner projects the vast majority of cloud security failures through 2026 will trace back to customer-side misconfiguration rather than provider failures, the responsibility mostly sits with the teams managing the account, not the infrastructure underneath it.&lt;/p&gt;

&lt;p&gt;Start with what's already available: enable MFA across every account with storage access, audit current IAM permissions for anything broader than necessary, confirm encryption coverage extends to backups and integrations, and set up basic access monitoring if it isn't already running. None of these steps require a large budget. They require someone to actually go through the settings and fix what's been left open by default.&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>From Enigma to Modern Ciphers: A Short History of Secret Codes</title>
      <dc:creator>Fu'ad Husnan</dc:creator>
      <pubDate>Sat, 15 Aug 2026 07:38:27 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/from-enigma-to-modern-ciphers-a-short-history-of-secret-codes-4po7</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/from-enigma-to-modern-ciphers-a-short-history-of-secret-codes-4po7</guid>
      <description>&lt;p&gt;Secret codes decided the outcome of World War II before a single soldier read the message they protected. The German military trusted a typewriter-sized machine called Enigma to scramble its orders into what looked like random noise, and for years that trust was justified. Then a small group of Polish mathematicians, followed by the codebreakers at Bletchley Park, found the cracks. The story of how that happened, and what came after it, is really the story of modern cryptography.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Commercial Invention Turned Into a Weapon
&lt;/h2&gt;

&lt;p&gt;Enigma wasn't built for war. German engineer Arthur Scherbius patented the machine in 1918, hoping to sell it to banks and businesses that wanted to protect commercial correspondence. He founded a company to manufacture it and showed early models at a trade fair in 1923, but civilian demand never took off the way he expected. The German military saw something Scherbius's business customers didn't: a fast, repeatable way to encrypt battlefield communications without relying on codebooks that could be lost or stolen.&lt;/p&gt;

&lt;p&gt;By the late 1920s, the German armed forces had adopted modified versions of Enigma for their own use, and mass production ramped up through the 1930s. The machine used a set of rotating wheels, each wired internally to swap one letter for another. Every keystroke advanced at least one rotor, so pressing the same letter twice in a row rarely produced the same encrypted output twice. A plugboard added a further layer of substitution before the signal ever reached the rotors. The number of possible settings ran into the billions, and German commanders had good reason to believe the system was unbreakable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Poles Found the First Crack
&lt;/h2&gt;

&lt;p&gt;The first real breakthrough didn't come from Britain, and it didn't come during the war. It came from Poland in the early 1930s, years before the German invasion. French intelligence had obtained stolen Enigma operating manuals and passed them to the Polish Cipher Bureau, which put the documents to far better use than the French had. Mathematician Marian Rejewski used the leaked material, combined with pure mathematical analysis, to work out the internal wiring of the rotors without ever touching a real machine.&lt;/p&gt;

&lt;p&gt;That achievement is easy to undervalue today because Bletchley Park gets most of the credit in popular accounts. But Rejewski's team had reconstructed a working replica of Enigma and built early codebreaking machines years before the war started. When Germany's invasion of Poland became a near-certainty in 1939, Polish intelligence handed their findings, along with physical Enigma replicas, to British and French codebreakers. That handoff gave Bletchley Park a running start it would not otherwise have had.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bletchley Park and the Bombe
&lt;/h2&gt;

&lt;p&gt;Britain's Government Code and Cypher School, based at Bletchley Park, absorbed the Polish research and pushed it further. As Germany added complexity to Enigma, including more rotor options and stricter operating procedures, the Polish techniques stopped working on their own. Alan Turing, working alongside other mathematicians and engineers, designed an electromechanical device called the Bombe that could test thousands of possible rotor settings far faster than any human. By 1940, the Bombe was producing usable decryptions of German military traffic.&lt;/p&gt;

&lt;p&gt;The intelligence generated by this effort, codenamed Ultra, gave the Allies insight into German troop movements, naval deployments, and strategic planning throughout the war. Because Germany had shared Enigma technology with Japan, some of the same codebreaking techniques contributed to Allied successes in the Pacific theater as well. Some historians consider the cracking of Enigma one of the single most consequential Allied achievements of the war, not because it ended any one battle, but because it removed the fog of war from an adversary who believed their communications were completely secure.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Rotors to Algorithms
&lt;/h2&gt;

&lt;p&gt;Enigma belongs to a category cryptographers now call classical cryptography: methods built on physical devices, pencil-and-paper substitution, or mechanical rotors. Once electronic computing matured after the war, the field shifted almost entirely toward mathematics. Encryption stopped being something you could hold in your hand and became something expressed in algorithms designed to resist attacks that no mechanical device could ever face.&lt;/p&gt;

&lt;p&gt;The first widely adopted standard for the computer age was the Data Encryption Standard, developed in the 1970s and adopted by the U.S. government for protecting sensitive but unclassified data. DES used a fixed-length key to scramble data in blocks, and for a while it was good enough. But computing power grew faster than DES's key length could keep up with, and by the late 1990s brute-force attacks against it were practical rather than theoretical.&lt;/p&gt;

&lt;p&gt;That gap set the stage for the algorithm most people rely on today without realizing it. In 2001, the National Institute of Standards and Technology replaced DES with the Advanced Encryption Standard. AES is a symmetric cipher, meaning the same key both encrypts and decrypts the data, but it uses a much longer key than DES and has proven remarkably resistant to attack ever since. AES now secures everything from Wi-Fi traffic to encrypted messaging apps to the files on your laptop's hard drive.&lt;/p&gt;

&lt;p&gt;Here's a simplified illustration of AES-style symmetric encryption in Python, using a well-established cryptography library rather than a hand-rolled implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;cryptography&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;fernet&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Fernet&lt;/span&gt;

&lt;span class="c1"&gt;# Generate a key and use it to create a Fernet cipher instance.
# Fernet uses AES under the hood, combined with authentication.
&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Fernet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_key&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;cipher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Fernet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Meet at the north bridge at 0600.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;encrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;decrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encrypted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Encrypted:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encrypted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Decrypted:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decrypted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code produces ciphertext that looks as meaningless to an outside observer as an intercepted Enigma transmission once did, except the underlying math would take longer than the age of the universe to brute-force with current computers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solving the Key Distribution Problem
&lt;/h2&gt;

&lt;p&gt;Symmetric ciphers like DES and AES share a weakness that goes all the way back to Enigma: both parties need the same secret key, and getting that key safely into the right hands is its own security problem. German operators had to distribute rotor settings through printed codebooks, which is exactly the kind of physical vulnerability that let the Allies gain footholds in the first place.&lt;/p&gt;

&lt;p&gt;In 1977, Ron Rivest, Adi Shamir, and Leonard Adleman introduced a different approach: public key cryptography, later named RSA after its creators. RSA lets each user hold a private key that never has to be shared, paired with a public key that anyone can use to encrypt a message meant only for that person. The security of the system rests on how difficult it is to factor the product of two very large prime numbers. Multiplying two large primes together is fast; reversing the process without knowing the original numbers is, for practical purposes, not.&lt;/p&gt;

&lt;p&gt;RSA and the closely related Diffie-Hellman key exchange solved the distribution problem that had haunted cryptography since Enigma. Two parties who have never met can now agree on a shared secret over an open channel that an eavesdropper is watching the entire time, and the eavesdropper still can't recover the secret. That capability underpins the padlock icon in a web browser and the encrypted connection behind most everyday internet transactions.&lt;/p&gt;

&lt;p&gt;A basic illustration of asymmetric &lt;a href="https://msf.telkomuniversity.ac.id/apa-itu-enkripsi-rahasia-di-balik-keamanan-data-digital/" rel="noopener noreferrer"&gt;encryption&lt;/a&gt; looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;cryptography.hazmat.primitives.asymmetric&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;rsa&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;cryptography.hazmat.primitives&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hashes&lt;/span&gt;

&lt;span class="c1"&gt;# Generate a private/public key pair.
&lt;/span&gt;&lt;span class="n"&gt;private_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rsa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_private_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;public_exponent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;65537&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;public_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;private_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;public_key&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Confirm rendezvous coordinates.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Encrypt with the public key.
&lt;/span&gt;&lt;span class="n"&gt;ciphertext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;public_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;OAEP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;mgf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MGF1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;algorithm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;hashes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SHA256&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
        &lt;span class="n"&gt;algorithm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;hashes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SHA256&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Only the matching private key can decrypt it.
&lt;/span&gt;&lt;span class="n"&gt;plaintext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;private_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;OAEP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;mgf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MGF1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;algorithm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;hashes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SHA256&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
        &lt;span class="n"&gt;algorithm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;hashes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SHA256&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plaintext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In practice, most secure systems combine both approaches. RSA or a similar algorithm handles the initial handshake and key exchange, then AES takes over for the bulk encryption of the actual data, since symmetric ciphers are much faster for large volumes of traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Next Disruption: Quantum Computing
&lt;/h2&gt;

&lt;p&gt;Every era of cryptography has eventually met a method that broke it, and the current era is no exception. Quantum computers, if built at sufficient scale, threaten to undo the mathematical assumptions behind RSA and other public key systems. Shor's algorithm, a quantum algorithm developed in the 1990s, can in theory factor large numbers efficiently enough to break RSA encryption that would otherwise take classical computers longer than the age of the universe to crack. Elliptic curve cryptography, widely used as a more compact alternative to RSA, faces a similar threat because it also depends on a mathematical problem that quantum computers can solve far faster than classical ones.&lt;/p&gt;

&lt;p&gt;Symmetric ciphers like AES fare better against this threat. Grover's algorithm, another quantum technique, only offers a quadratic speedup against symmetric encryption rather than the exponential break Shor's algorithm poses to RSA. Practically, that means AES-256 is expected to retain roughly 128 bits of effective security even against a capable quantum adversary, which remains strong by current standards, while AES-128 would be considered weaker and worth upgrading.&lt;/p&gt;

&lt;p&gt;The response to this looming risk is already underway. The National Institute of Standards and Technology has finalized post-quantum cryptography standards designed to resist both classical and quantum attacks. One of them, a key-encapsulation mechanism built on lattice-based mathematics rather than prime factorization, is intended to eventually replace RSA and Diffie-Hellman for establishing shared secrets. A companion standard covers digital signatures using the same lattice-based foundation. Because large-scale quantum computers capable of actually breaking RSA don't exist yet, organizations have time to migrate, but government guidance already recommends phasing out smaller RSA keys well before 2035 and treating today's encrypted traffic as potentially exposed to future decryption once quantum capability catches up.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the History Actually Teaches
&lt;/h2&gt;

&lt;p&gt;Every generation of cryptography has followed the same arc: a method gets adopted with confidence, someone finds a flaw the designers didn't anticipate, and the field moves to something stronger. Enigma's designers didn't imagine that stolen manuals and careful mathematics could reconstruct their rotor wiring from the outside. DES's designers didn't anticipate how cheap computing power would become. RSA's designers built a system that has held up for nearly five decades, but even that system now has a visible expiration date on the horizon.&lt;/p&gt;

&lt;p&gt;None of this means today's encryption is weak. AES remains extremely difficult to break by any known method, classical or quantum, and RSA is still safe for the threats that exist right now. What history shows is that cryptography is never a finished project. It's a continuous negotiation between people trying to keep secrets and people trying to expose them, and the winner of that negotiation has changed hands more than once. Anyone building or relying on secure systems today would do well to remember that the "unbreakable" label has never lasted as long as it sounded like it would.&lt;/p&gt;

</description>
      <category>cryptography</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>How to Safely Store and Encrypt API Credentials in Production</title>
      <dc:creator>Fu'ad Husnan</dc:creator>
      <pubDate>Fri, 14 Aug 2026 12:32:01 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/how-to-safely-store-and-encrypt-api-credentials-in-production-e72</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/how-to-safely-store-and-encrypt-api-credentials-in-production-e72</guid>
      <description>&lt;p&gt;Every leaked API credential starts the same way: a key that was supposed to stay private ends up somewhere it shouldn't, whether that's a public GitHub repo, a log file, or a Slack message. Learning to store and encrypt API credentials in production correctly is one of the highest-leverage security habits a backend team can build, because a single exposed key can grant an attacker the same access your own services have.&lt;/p&gt;

&lt;p&gt;This guide walks through the practical mechanics of credential storage, starting with what not to do, then moving through environment variables, dedicated secrets managers, encryption at rest, and rotation strategies that keep systems running without downtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Hardcoded Credentials
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Never do this
&lt;/span&gt;&lt;span class="n"&gt;DATABASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;postgresql://admin:SuperSecret123@prod-db.internal:5432/app&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;STRIPE_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk_live_51H8x2KJ9...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hardcoding credentials directly into source files feels convenient during early development, but it creates a permanent record of the secret in version control history. Even deleting the line in a later commit doesn't remove it, since Git preserves every prior revision unless the history is explicitly rewritten and force-pushed. Automated scanners run by attackers crawl public and leaked private repositories specifically looking for patterns like &lt;code&gt;sk_live_&lt;/code&gt;, &lt;code&gt;AKIA&lt;/code&gt;, or &lt;code&gt;postgresql://&lt;/code&gt; followed by a password.&lt;/p&gt;

&lt;p&gt;The fix isn't complicated, but it requires discipline across the whole team. Credentials need to live outside the codebase entirely, in a system designed to hold them, restrict access to them, and audit who touches them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment Variables: The Baseline
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# .env file (never committed to version control)&lt;/span&gt;
&lt;span class="nv"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgresql://admin:SuperSecret123@prod-db.internal:5432/app
&lt;span class="nv"&gt;STRIPE_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk_live_51H8x2KJ9...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;

&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;database_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;stripe_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;STRIPE_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Environment variables are the minimum viable approach to credential storage. They keep secrets out of source code, and most deployment platforms, including Heroku, Render, and container orchestrators like Kubernetes, offer native support for injecting them at runtime. The &lt;code&gt;.env&lt;/code&gt; file itself must be listed in &lt;code&gt;.gitignore&lt;/code&gt; from the very first commit, since a single accidental push defeats the entire purpose.&lt;/p&gt;

&lt;p&gt;Environment variables have real limits, though. They're visible to any process running under the same user; they show up in crash dumps and debugging tools, and they don't support fine-grained access control or automatic rotation. For a solo developer's side project, environment variables are often sufficient. For a production system handling customer data or payments, they're a starting point, not an ending point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Secrets Managers for Production Systems
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_secret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;secret_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us-east-1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;secretsmanager&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_secret_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SecretId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;secret_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SecretString&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;credentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_secret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prod/api-credentials&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;stripe_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stripe_api_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dedicated secrets managers such as AWS Secrets Manager, HashiCorp Vault, and Google Secret Manager solve the problems environment variables can't. Every one of these tools encrypts secrets at rest by default, logs every access attempt, and supports IAM-based or policy-based permissions so that only specific services or roles can retrieve specific credentials. A payments microservice can be granted access to the Stripe key without also being able to read the database password for an unrelated service.&lt;/p&gt;

&lt;p&gt;HashiCorp Vault takes this further with dynamic secrets, where the database credentials handed to an application are generated on demand and expire automatically after a set lease period.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault write database/config/production &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;plugin_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgresql-database-plugin &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;connection_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"postgresql://{{username}}:{{password}}@prod-db:5432/app"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;allowed_roles&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"app-role"&lt;/span&gt;

vault &lt;span class="nb"&gt;read &lt;/span&gt;database/creds/app-role
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of a single long-lived password shared across every service instance, each application process requests its own short-lived credential. If that credential leaks, it becomes worthless after the lease expires, often within an hour, which dramatically narrows the window an attacker has to exploit it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encrypting Credentials at Rest
&lt;/h2&gt;

&lt;p&gt;Secrets managers handle encryption transparently, but there are cases where a team stores encrypted credentials in its own database or configuration store, for example, when building a multi-tenant SaaS product that needs to hold each customer's third-party &lt;a href="https://bif.telkomuniversity.ac.id/api-application-programming-interface-panduan-lengkap-dan-praktis/" rel="noopener noreferrer"&gt;API&lt;/a&gt; keys.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;cryptography.fernet&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Fernet&lt;/span&gt;

&lt;span class="c1"&gt;# Generate once, store the key in a KMS or secrets manager, never in code
&lt;/span&gt;&lt;span class="n"&gt;encryption_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Fernet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_key&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;cipher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Fernet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encryption_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Encrypting before storage
&lt;/span&gt;&lt;span class="n"&gt;plaintext_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customer_api_key_abc123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;encrypted_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plaintext_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Decrypting when the credential is actually needed
&lt;/span&gt;&lt;span class="n"&gt;decrypted_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encrypted_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;cryptography&lt;/code&gt; library's Fernet implementation provides authenticated symmetric encryption, meaning it detects if the ciphertext has been tampered with, not just whether it can be decrypted. The critical detail most teams get wrong is where the encryption key itself lives. Storing the encryption key in the same database as the encrypted credentials defeats the entire scheme, since anyone with database access gets both the lock and the key.&lt;/p&gt;

&lt;p&gt;The correct pattern uses envelope encryption: a cloud key management service such as AWS KMS or Google Cloud KMS holds a master key that never leaves the service, and that master key is used to encrypt a per-record data key, which in turn encrypts the actual credential.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;

&lt;span class="n"&gt;kms_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;encrypt_credential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plaintext_credential&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kms_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;KeyId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;key_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Plaintext&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;plaintext_credential&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CiphertextBlob&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decrypt_credential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ciphertext_blob&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kms_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CiphertextBlob&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ciphertext_blob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Plaintext&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this approach, even a full database dump gives an attacker only ciphertext. Decryption requires calling the KMS API, which is itself gated by IAM permissions and produces an audit trail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rotating Credentials Without Downtime
&lt;/h2&gt;

&lt;p&gt;Storing credentials securely solves half the problem. The other half is changing them regularly enough that a compromise, even an undetected one, has a limited shelf life. Manual rotation tends to get postponed indefinitely because it's disruptive, so the more durable fix is to make rotation a scheduled, low-risk event rather than an emergency procedure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rotate_database_credential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;secrets_client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;secret_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;new_password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_secure_password&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;update_database_user_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;secrets_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_secret_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;SecretId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;secret_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;SecretString&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;new_password&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AWS Secrets Manager and Vault both support automatic rotation on a defined schedule, typically by invoking a Lambda function or a rotation plugin that updates the credential in the target system and the secrets store in the same transaction. The key design principle is supporting two valid credentials briefly during the transition window, so that in-flight requests using the old credential don't fail while new requests pick up the new one. Zero-downtime rotation is what separates a mature credential program from one that just checks a compliance box.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes That Undermine Credential Security
&lt;/h2&gt;

&lt;p&gt;A surprising number of credential leaks happen not because a team skipped secrets management entirely, but because of gaps around the edges of an otherwise reasonable setup. Logging frameworks that print full request objects, including headers with &lt;code&gt;Authorization: Bearer&lt;/code&gt; tokens, are a frequent culprit. CI/CD pipelines that echo environment variables into build logs for debugging purposes are another, since those logs are often retained and searchable long after the debugging session ends.&lt;/p&gt;

&lt;p&gt;Shared credentials across environments cause similar damage. Using the same API key for staging and production means that a compromised staging environment, which usually has weaker monitoring, hands an attacker direct access to production data. Each environment deserves its own credentials, scoped to its own permissions, so that a breach in one doesn't cascade into the others.&lt;/p&gt;

&lt;p&gt;Getting API credential storage right isn't a single decision but a layered set of practices: keeping secrets out of source code, using a dedicated secrets manager instead of bare environment variables where the stakes justify it, applying envelope encryption when credentials must live in application-owned storage, and rotating on a schedule instead of waiting for an incident to force the issue. Teams that treat credential management as ongoing infrastructure work, rather than a one-time setup task, are the ones that avoid becoming the next breach headline. Audit your current credential storage against the practices above, and prioritize fixing whichever gap would cause the most damage if exploited first.&lt;/p&gt;

</description>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Protecting Microservices: Implementing End-to-End Encryption Across REST APIs</title>
      <dc:creator>Fu'ad Husnan</dc:creator>
      <pubDate>Fri, 14 Aug 2026 12:29:18 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/protecting-microservices-implementing-end-to-end-encryption-across-rest-apis-26hb</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/protecting-microservices-implementing-end-to-end-encryption-across-rest-apis-26hb</guid>
      <description>&lt;p&gt;End-to-end encryption across REST APIs is the difference between a microservices architecture that merely looks secure on a network diagram and one that actually resists a breach. Most teams encrypt traffic at the edge with TLS and stop there, trusting that once a request lands inside the cluster, the internal network is safe. That assumption breaks the moment an attacker compromises a single pod, a misconfigured sidecar, or a third-party dependency sitting between two services.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why TLS Alone Isn't Enough for Microservices
&lt;/h2&gt;

&lt;p&gt;TLS termination at a load balancer or API gateway protects data while it crosses the public internet, but it says nothing about what happens after that. In a typical Kubernetes deployment, dozens of services exchange JSON payloads over plaintext HTTP inside the cluster network, relying on network policies and namespace isolation as the only barrier between a legitimate request and a malicious one.&lt;/p&gt;

&lt;p&gt;That barrier is thinner than it looks. Container escapes, misrouted service meshes, and compromised CI/CD pipelines have all been used to intercept internal traffic that nobody expected to be readable. A payment service passing card tokens to a fraud-detection service, or an identity provider forwarding session claims to a dozen downstream consumers, is exposed the moment any one hop in that chain is compromised.&lt;/p&gt;

&lt;p&gt;End-to-end encryption closes this gap by encrypting the payload itself, not just the transport layer. Even if an attacker sits inside the network and captures every packet, the request body remains unreadable without the recipient's private key. This shifts the security model from "trust the network" to "trust nothing between sender and intended receiver," which is the assumption most zero-trust architectures are built on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encrypting the Payload with Hybrid Encryption
&lt;/h2&gt;

&lt;p&gt;Full asymmetric encryption of large JSON bodies is computationally expensive, so most production systems use a hybrid approach: a symmetric key encrypts the payload, and an asymmetric key pair encrypts that symmetric key. Here is a minimal Node.js example using AES-256-GCM for the payload and RSA-OAEP for the key exchange.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crypto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;encryptPayload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;recipientPublicKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;aesKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cipher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCipheriv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aes-256-gcm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;aesKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;final&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authTag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAuthTag&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encryptedKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publicEncrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;recipientPublicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;constants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RSA_PKCS1_OAEP_PADDING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;oaepHash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sha256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;aesKey&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;encryptedKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;encryptedKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;authTag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;authTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;encrypted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the receiving service, the private key decrypts the AES key first, then that key decrypts the payload. Only the service holding the corresponding private key can complete this chain, regardless of how many intermediate hops the request passed through.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;decryptPayload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;aesKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;privateDecrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;constants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RSA_PKCS1_OAEP_PADDING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;oaepHash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sha256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;encryptedKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decipher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createDecipheriv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aes-256-gcm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;aesKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;decipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAuthTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authTag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;decipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;decipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;final&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decrypted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern keeps CPU overhead low because AES handles the bulk of the data while RSA only ever encrypts a 32-byte key. GCM mode also provides built-in authentication through its tag, so tampering with the ciphertext in transit causes decryption to fail loudly rather than silently returning corrupted data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing Keys Without Creating a New Attack Surface
&lt;/h2&gt;

&lt;p&gt;Encryption is only as strong as the key management behind it, and this is where many implementations quietly fail. Hardcoding public keys in service configuration files, or worse, committing private keys to a repository, defeats the purpose of encrypting the payload in the first place.&lt;/p&gt;

&lt;p&gt;A dedicated key management system such as HashiCorp Vault, AWS KMS, or Google Cloud KMS should own key generation, rotation, and access control. Services request the keys they need at startup or per transaction, and every key request is logged, giving security teams an audit trail of exactly which service accessed which key and when.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Example Vault policy restricting a service to its own key path&lt;/span&gt;
&lt;span class="s"&gt;path "transit/keys/fraud-detection-service" {&lt;/span&gt;
  &lt;span class="s"&gt;capabilities = ["read"]&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="s"&gt;path "transit/decrypt/fraud-detection-service" {&lt;/span&gt;
  &lt;span class="s"&gt;capabilities = ["update"]&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key rotation deserves particular attention in a microservices context because dozens of services may depend on the same key pair. Rotating keys without downtime typically means supporting two active key versions simultaneously: the new key for outgoing requests and both the new and previous keys for decrypting incoming requests until every service has picked up the rotation. Vault's transit secrets engine handles this versioning natively, which removes the need to build custom rotation logic into each service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Applying Encryption Selectively Based on Data Sensitivity
&lt;/h2&gt;

&lt;p&gt;Encrypting every payload across every internal call sounds thorough, but it introduces latency and operational complexity that most systems don't need for low-sensitivity data like health checks or public catalog lookups. A more practical approach classifies data by sensitivity and applies end-to-end encryption only where the cost is justified.&lt;/p&gt;

&lt;p&gt;Personally identifiable information, authentication tokens, payment details, and health records typically warrant the full encryption treatment described above. Internal telemetry, cache invalidation events, and service discovery pings usually do not, since TLS at the transport layer already protects them adequately for their risk profile.&lt;/p&gt;

&lt;p&gt;This classification should live in a shared schema or &lt;a href="https://bis-sby.telkomuniversity.ac.id/apa-itu-api-pengertian-jenis-dan-cara-kerjanya/" rel="noopener noreferrer"&gt;API&lt;/a&gt; contract rather than being decided ad hoc by individual teams. A common pattern is to tag fields in the API specification itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"userId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ssn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"x-encryption"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"required"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lastLoginTimestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Middleware can then read these annotations and automatically apply field-level encryption to marked properties before the request leaves the service, rather than encrypting the entire payload indiscriminately. This keeps performance overhead proportional to actual risk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Encrypted Payloads at the API Gateway
&lt;/h2&gt;

&lt;p&gt;API gateways complicate end-to-end encryption because their normal job includes inspecting requests for routing, rate limiting, and logging. If the payload is encrypted before it reaches the gateway, the gateway can no longer read the fields it might normally use for these functions.&lt;/p&gt;

&lt;p&gt;The practical resolution is to separate what the gateway needs to see from what it doesn't. Routing metadata, authentication headers, and rate-limit identifiers stay in plaintext HTTP headers, while the sensitive request body travels encrypted end-to-end between the originating and terminating services. The gateway forwards the encrypted envelope without attempting to parse it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Gateway-level routing based on plaintext headers only&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;targetService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-target-service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isValidToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authToken&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unauthorized&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;proxyRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This division keeps the gateway's operational functions intact without forcing it to become a trusted party for decrypting sensitive fields, which would otherwise reintroduce the exact single point of failure that end-to-end encryption is meant to eliminate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing and Verifying the Encryption Pipeline
&lt;/h2&gt;

&lt;p&gt;An encryption implementation that hasn't been tested against failure modes is a liability disguised as a feature. Beyond confirming that a valid request encrypts and decrypts correctly, the test suite needs to verify that tampered ciphertext, expired keys, and mismatched key versions all fail safely rather than falling back to plaintext processing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rejects payload with tampered authentication tag&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;envelope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;encryptPayload&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;ssn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123-45-6789&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authTag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;decryptPayload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toThrow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Load testing matters just as much as correctness testing here, since RSA operations are notably slower than symmetric encryption and can become a bottleneck under high request volume if key exchange happens on every single call instead of being cached or amortized across a session.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bringing It Together
&lt;/h2&gt;

&lt;p&gt;End-to-end encryption across REST APIs isn't a single library or a checkbox in a security audit; it's an architectural decision that touches key management, gateway design, and how teams classify their own data. The hybrid encryption pattern keeps performance reasonable, a dedicated key management system keeps keys out of source code, and selective field-level encryption keeps the overhead proportional to actual risk rather than applying uniform cost to every request regardless of sensitivity.&lt;/p&gt;

&lt;p&gt;Teams evaluating this for their own microservices should start narrow: pick the one or two services handling the most sensitive data, implement the encryption envelope pattern there, and measure the latency impact before rolling it out further. Trying to encrypt everything on day one is how these projects stall; proving the pattern on a single high-value service is how they ship.&lt;/p&gt;

</description>
      <category>api</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Top Ways to Keep User Data Safe from Hackers</title>
      <dc:creator>Fu'ad Husnan</dc:creator>
      <pubDate>Sat, 08 Aug 2026 02:56:46 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/top-ways-to-keep-user-data-safe-from-hackers-4aon</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/top-ways-to-keep-user-data-safe-from-hackers-4aon</guid>
      <description>&lt;p&gt;If you run any product that touches personal information, you need a real plan to keep user data safe from hackers, not just a checkbox compliance policy. The threat landscape has shifted fast: breach costs, attacker sophistication, and the sheer number of incidents have all climbed in the last two years, and the organizations getting hit hardest are usually the ones that treated security as an afterthought rather than a design requirement.&lt;/p&gt;

&lt;p&gt;The numbers make the stakes clear. The global average cost of a data breach now sits around $4.44 million, and in the United States that figure climbs past $10 million per incident. Breaches that take longer than 200 days to contain cost noticeably more than those caught early, which means detection speed is not a nice-to-have; it is one of the biggest levers you have over your own exposure. Meanwhile, more than a third of breaches now originate through a vendor or third-party integration rather than a direct attack on the core product, and AI-assisted phishing is expected to account for a large share of intrusions by the end of the year. None of this is meant to scare you into paralysis. It is meant to explain why the practices below matter more now than they did five years ago.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encrypt Data at Rest and in Transit
&lt;/h2&gt;

&lt;p&gt;Encryption is the baseline, not the finish line. Data in transit should run over TLS 1.2 or higher everywhere, including internal service-to-service calls that teams often skip because "it's just internal traffic." Data at rest deserves the same discipline: database-level encryption, encrypted backups, and encrypted object storage buckets close off an entire category of attacks where a leaked credential or misconfigured storage bucket would otherwise hand over plaintext records.&lt;/p&gt;

&lt;p&gt;A common mistake is treating encryption as something you can bolt on later. Retrofitting encryption into a schema that already has millions of plaintext rows is painful and error-prone, so it is worth building this in from day one, even for an early-stage product with a small user base. Cloud providers like AWS, Google Cloud, and Azure now offer encryption at rest by default for most managed services, but default settings are not the same as verified settings. Audit them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hash and Salt Passwords Properly
&lt;/h2&gt;

&lt;p&gt;Storing passwords is one of the few places where getting the implementation detail wrong can single-handedly turn a minor breach into a catastrophic one. Plaintext and even simple MD5 or SHA-1 hashes are not acceptable for password storage; both can be reversed at scale using modern hardware. The standard today is a slow, memory-hard hashing algorithm such as bcrypt, scrypt, or Argon2, combined with a unique salt per user so that identical passwords do not produce identical hashes.&lt;/p&gt;

&lt;p&gt;Here is a minimal example using bcrypt in Node.js, which handles salting automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bcrypt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saltRounds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;hashPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plainTextPassword&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plainTextPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;saltRounds&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;verifyPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plainTextPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;storedHash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isMatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plainTextPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;storedHash&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;isMatch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;saltRounds&lt;/code&gt; value controls how computationally expensive each hash operation is. Raising it slows down both legitimate logins and brute-force attempts, so it should be tuned against your server's actual hardware rather than copied blindly from a tutorial. If you are building in Python, &lt;code&gt;argon2-cffi&lt;/code&gt; offers similar protection with Argon2, which won the Password Hashing Competition and is generally recommended for new systems over bcrypt where the library ecosystem supports it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enforce Multi-Factor Authentication
&lt;/h2&gt;

&lt;p&gt;Passwords alone are no longer a sufficient gate, even well-hashed ones, because credential stuffing and phishing continue to be the most common way attackers get in. Security researchers have found that the overwhelming majority of breaches, often cited between 77% and 95%, still trace back to human error or manipulation rather than a novel technical exploit. Multi-factor authentication directly addresses this by requiring a second proof of identity, whether that's a time-based one-time code, a push notification, or a hardware security key.&lt;/p&gt;

&lt;p&gt;Rolling out MFA does not have to mean forcing it on every user immediately. A staged approach works well: require it for admin and privileged accounts first, since those carry the most damage potential if compromised, then extend it to all users with a grace period and clear in-product messaging about why it matters. Support for FIDO2 and WebAuthn has matured enough that passkeys are now a realistic option for consumer products, and they remove the phishing risk entirely since there is no shared secret for an attacker to steal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Apply the Principle of Least Privilege
&lt;/h2&gt;

&lt;p&gt;Every account, service, and API key in your system should have exactly the permissions it needs and nothing more. This sounds obvious, but in practice, permissions creep over time as teams grant broad access to move faster and never revisit it. A support engineer who needs to view account status does not need write access to the billing &lt;a href="https://bif.telkomuniversity.ac.id/database-definisi-pengertian-manfaat-jenis-dan-contohnya/" rel="noopener noreferrer"&gt;database&lt;/a&gt;. A microservice that reads inventory data does not need permission to delete user records.&lt;/p&gt;

&lt;p&gt;Role-based access control (RBAC) and, for more complex systems, attribute-based access control (ABAC) give you a structured way to enforce this instead of relying on ad hoc decisions made under deadline pressure. Regular access reviews, ideally automated and run quarterly at minimum, catch the accounts that accumulated permissions they no longer need, including former employees and deprecated service accounts that were never fully decommissioned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Patch and Update Continuously
&lt;/h2&gt;

&lt;p&gt;Unpatched software remains one of the most exploited entry points, largely because attackers automate the search for known vulnerabilities in outdated dependencies, and that automation moves faster than most manual patch cycles. A dependency scanning tool integrated into your CI pipeline, such as Dependabot, Snyk, or Renovate, flags vulnerable packages before they ship rather than after an incident response team finds them during a post-mortem.&lt;/p&gt;

&lt;p&gt;Patch management extends beyond application code to the infrastructure layer: operating systems, container base images, and third-party libraries baked into your build all need a defined update cadence. Teams that treat patching as a monthly maintenance chore instead of a continuous process tend to be the ones still running vulnerable versions six months after a CVE was published and publicly disclosed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitor, Log, and Have an Incident Response Plan
&lt;/h2&gt;

&lt;p&gt;You cannot respond to what you cannot see. Centralized logging across application servers, databases, and authentication systems, paired with anomaly detection, is what turns a breach from a months-long undetected compromise into a same-day catch. The data backs this up directly: incident response plans are consistently cited as one of the single largest cost reducers in breach economics, saving organizations millions per incident simply because the team already knows who does what in the first hour.&lt;/p&gt;

&lt;p&gt;A workable incident response plan does not need to be a hundred-page document. It needs clear ownership of who declares an incident, a communication chain that does not depend on one person being reachable, and a tested process for isolating affected systems without destroying forensic evidence. Run a tabletop exercise at least once a year. Teams that have practiced a breach scenario respond meaningfully faster than teams encountering the process for the first time during a real one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vet Third-Party Vendors and Integrations
&lt;/h2&gt;

&lt;p&gt;Supply chain risk has grown into one of the most significant blind spots in modern security programs, with vendor and third-party compromises now behind a substantial share of all breaches. Every SaaS tool, API integration, and outsourced service that touches user data extends your attack surface, whether or not your own code changes at all.&lt;/p&gt;

&lt;p&gt;Before integrating a new vendor, ask for their SOC 2 report or equivalent attestation, review what data they actually need versus what they're requesting, and scope API keys and permissions as narrowly as the integration allows. This vetting process should not stop after signing the contract. Vendors get breached too, and your incident response plan should account for the scenario where the compromise originates outside your own infrastructure entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Security Into the Culture, Not Just the Stack
&lt;/h2&gt;

&lt;p&gt;Tools and configurations matter, but they only work if the people building and operating the product treat security as part of the job rather than a separate team's problem. That means code review that actually checks for security issues, not just style, and it means giving engineers the context to understand why a control exists instead of just enforcing it as a rule handed down from above.&lt;/p&gt;

&lt;p&gt;Keeping user data safe from hackers is not a project with an end date. It is an ongoing practice that adjusts as attackers change tactics and as your own product surface grows. The organizations that handle this well are rarely the ones with the biggest security budgets; they are the ones that built encryption, access control, and monitoring into their default way of shipping software, so that protecting user data is simply what building the product looks like.&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>database</category>
    </item>
    <item>
      <title>Why Autonomous Databases Are Changing IT Jobs</title>
      <dc:creator>Fu'ad Husnan</dc:creator>
      <pubDate>Sat, 08 Aug 2026 02:51:48 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/why-autonomous-databases-are-changing-it-jobs-3ki0</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/why-autonomous-databases-are-changing-it-jobs-3ki0</guid>
      <description>&lt;p&gt;Autonomous databases are quietly rewriting what it means to work in database administration, and the change has almost nothing to do with robots taking over server rooms. It has to do with time. A platform like Oracle Autonomous Database or a managed service such as Amazon RDS now performs the patching, backups, tuning, and scaling that used to consume most of a database administrator's week, and that shift is forcing IT departments to decide what a DBA is actually for once the maintenance work disappears.&lt;/p&gt;

&lt;p&gt;The term "autonomous" gets thrown around loosely, so it helps to be precise about what these systems actually do on their own. An autonomous &lt;a href="https://smb.telkomuniversity.ac.id/cerita-telutizen/apa-itu-basis-data-panduan-lengkap-belajar-di-telkom-university/" rel="noopener noreferrer"&gt;database&lt;/a&gt; applies security patches without downtime, monitors query performance and adjusts indexing or memory allocation in response, scales compute and storage up or down based on live workload, and runs automated backups with point-in-time recovery built in. None of this requires a human to log in at 2 a.m. because a batch job is choking on disk space. That single change, removing the pager duty that defined DBA life for two decades, is the real disruption, not some abstract AI takeover narrative.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the automation actually replaces
&lt;/h2&gt;

&lt;p&gt;The tasks disappearing first are the ones that were always the most repetitive: routine patching, manual backup verification, disk space monitoring, and first-pass performance tuning. These are precisely the responsibilities that showed up in every DBA job description for the last twenty years, and they are also the ones most easily codified into rules a machine can execute. A McKinsey estimate cited by Research.com projects that up to 45% of database-related tasks could be automated by 2030, which lines up with what practitioners are already reporting on the ground.&lt;/p&gt;

&lt;p&gt;The pattern is not unique to Oracle's ecosystem, either. Analysis from AI Changing Work breaks down DBA task exposure into a "theoretical" ceiling and an "observed" reality: DBAs show 82% theoretical exposure to automation but only 22% observed exposure so far, a 60-point gap that reflects how slowly organizations actually adopt tools even when the technology to automate a task already exists. That gap matters more than the headline number. It means the disruption is real but staggered, arriving fastest in cloud-native shops and slowest in regulated industries running decades-old Oracle or SQL Server estates that nobody wants to touch mid-migration.&lt;/p&gt;

&lt;p&gt;The efficiency numbers coming from vendors, while self-interested, are still striking. IT Convergence, an Oracle-focused consultancy, reports that organizations running Oracle's Autonomous AI Database saw DBA teams that were 66% more efficient, infrastructure teams 48% more efficient, and a 436% return on investment over three years in an IDC business value study. Even discounting for vendor optimism, a number that large signals a structural shift in how database operations budgets get allocated, not a marginal productivity bump.&lt;/p&gt;

&lt;h2&gt;
  
  
  The jobs that are shrinking, and the ones taking their place
&lt;/h2&gt;

&lt;p&gt;What's disappearing is the DBA-as-technician role: the person whose primary value was keeping the lights on through manual intervention. What's replacing it is closer to a data strategist or platform architect, someone who spends less time firefighting and more time on data modeling, access design, and the architectural decisions that automation still can't make on its own. Old-guard, on-premise environments still need dedicated hands for the things automation genuinely cannot touch, since performance troubleshooting on a legacy cluster and the judgment calls around schema design remain stubbornly human work.&lt;/p&gt;

&lt;p&gt;This reshuffling shows up clearly in compensation data. KORE1's 2026 placement data shows that cloud platform skills, specifically AWS, Azure, and GCP, add 15 to 25% to a DBA's salary and represent the single biggest differentiator in the market this year, while AI and ML data engineering skills add another 20 to 30% for DBAs who can build and manage the pipelines feeding machine learning models. Certification data tells a similar story: TekRecruiter reports that AWS Database Specialty holders average $146,000 in compensation compared to $105,000 to $110,000 for uncertified peers, a gap of roughly 30 to 40%. Routine administration simply doesn't command that kind of premium anymore, because the routine part is exactly what got automated away.&lt;/p&gt;

&lt;p&gt;The adjacent field absorbing much of this displaced talent is data engineering. Veriipro's 2026 career guide notes that database administrators are one of the more common entry points into big data engineering roles, since they already bring valuable knowledge of data modeling and SQL, and the transition typically takes six to twelve months of focused skill-building, a portfolio project or two, and a certification. DataExpert's transition guide backs this up with numbers, reporting median data engineering salaries of $131,000, senior roles reaching up to $220,000, and demand expected to double between 2025 and 2030. For a DBA whose day-to-day maintenance work just got absorbed by an autonomous platform, that's a well-worn exit ramp rather than a leap into the unknown.&lt;/p&gt;

&lt;h2&gt;
  
  
  A concrete example: what "self-tuning" looks like
&lt;/h2&gt;

&lt;p&gt;It helps to see what the automation is actually replacing rather than take the marketing language at face value. A traditional DBA workflow for diagnosing a slow query on Oracle might start with something manual like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Traditional manual diagnostic: DBA runs this by hand&lt;/span&gt;
&lt;span class="c1"&gt;-- after a user reports a slow report&lt;/span&gt;
&lt;span class="k"&gt;EXPLAIN&lt;/span&gt; &lt;span class="n"&gt;PLAN&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;order_date&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SYSDATE&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DBMS_XPLAN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DISPLAY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- If the plan shows a full table scan, the DBA decides&lt;/span&gt;
&lt;span class="c1"&gt;-- whether to add an index, gather fresh statistics,&lt;/span&gt;
&lt;span class="c1"&gt;-- or rewrite the query, then applies the fix by hand&lt;/span&gt;
&lt;span class="c1"&gt;-- and monitors the result manually.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On an autonomous platform, that entire loop- detection, diagnosis, and remediation- runs without a human triggering it. Oracle's Automatic Indexing feature, for example, continuously monitors SQL workloads, creates candidate indexes, tests them against the actual query pattern, and only makes them visible to the optimizer once it confirms they improve performance without regressing anything else. The DBA's role shifts from running the &lt;code&gt;EXPLAIN PLAN&lt;/code&gt; and deciding what to do about it, to setting the policies that govern what the system is allowed to change on its own, and reviewing the audit trail afterward. That's a genuinely different skill set: less muscle memory with diagnostic commands, more comfort with governance, monitoring dashboards, and knowing when to override the automation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The DBA-is-dead narrative is older than it looks
&lt;/h2&gt;

&lt;p&gt;It's worth some skepticism toward claims that autonomous technology spells the end of the DBA profession, because this specific prediction has a long and consistently wrong track record. Larry Ellison declared Oracle 8i's self-managing features "the death of the DBA" back in 1996, made the same claim again when Oracle Autonomous Database launched in 2017, and repeated it once more in 2023, describing the platform's AI module as having replaced DBAs outright. Each time, the role adapted instead of vanishing. A learnomate.org analysis of the 2018 wave of self-driving Oracle databases put it plainly: repetitive work like backup, restoration, patching, and upgrades can be automated, but performance still has to be handled by a DBA, and the role can change without the job disappearing.&lt;/p&gt;

&lt;p&gt;That said, the pressure on the people still doing the job is real and shows up in retention data, not just automation forecasts. SolarWinds' 2025 State of Database Report, drawing on responses from over a thousand IT professionals, found that one in three DBAs is considering a career move as demands on the role increase, driven by a disconnect between what executives expect and what DBAs are actually experiencing day to day. Automation is removing some of the grinding maintenance work, but it's simultaneously raising expectations for what the remaining, more strategic work should look like, and not every organization is managing that transition well.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means if you're planning a career around databases
&lt;/h2&gt;

&lt;p&gt;For anyone currently in or entering database work, the practical takeaway is to stop optimizing for platform-specific maintenance trivia and start building judgment that automation can't replicate. Cloud platform fluency, comfort with AI-assisted pipelines, and the architectural thinking needed to design systems rather than just keep them running are where the compensation data, the job transition patterns, and the vendor efficiency claims all point in the same direction. The maintenance work that defined the DBA role for a generation is being absorbed into the platform itself, and the professionals thriving through that shift are the ones treating it as a reason to move up the stack rather than a threat to argue against.&lt;/p&gt;

&lt;p&gt;If you're weighing whether to specialize deeper into a legacy platform or pivot toward cloud-native and AI-adjacent data work, the data available right now favors making that pivot deliberately, on your own timeline, rather than waiting for a layoff notice to force the decision.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>database</category>
    </item>
    <item>
      <title>Building Smarter Cloud Data Storage</title>
      <dc:creator>Fu'ad Husnan</dc:creator>
      <pubDate>Sat, 08 Aug 2026 02:40:06 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/building-smarter-cloud-data-storage-4jof</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/building-smarter-cloud-data-storage-4jof</guid>
      <description>&lt;p&gt;Smarter cloud data storage is no longer a nice-to-have for engineering teams; it is the difference between a predictable infrastructure bill and a monthly finance escalation. Object storage has become the default home for logs, backups, media, and now the training sets and embeddings that power AI workloads, and the sheer volume makes careless architecture expensive fast. Global cloud storage spend has already crossed the $120 billion mark, and industry data suggests roughly half of that spend goes toward fees and access charges rather than raw capacity. Building a smarter system means designing for how data actually gets used, not just where it gets dumped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Storage Costs Outgrow Storage Volume
&lt;/h2&gt;

&lt;p&gt;The instinct when a storage bill spikes is to blame growth in data volume. In practice, the bigger driver is usually access pattern mismatch: hot-tier pricing applied to cold data, synchronous replication applied to disposable logs, or small-object overhead multiplying across millions of files. Retrieval fees, egress charges, and API operation costs routinely push real-world spend two to five times higher than the advertised per-gigabyte rate. A team that only tracks $/GB is measuring the wrong number.&lt;/p&gt;

&lt;p&gt;Multi-cloud setups make this worse through data gravity. Moving large datasets between providers to chase a marginally cheaper compute rate rarely pays off once egress is factored in. The more durable strategy is to pin data to the provider that already hosts the compute using it, and treat cross-cloud movement as an exception that requires justification, not a default workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing Storage Around Access Frequency, Not File Age
&lt;/h2&gt;

&lt;p&gt;Most teams default to lifecycle rules based on file age: move anything older than 30 days to a cooler tier. Age is a weak proxy for access frequency. A financial report from six months ago might still be queried daily by an analytics dashboard, while a log file generated an hour ago may never be read again. Smarter systems tag objects by expected access pattern at write time, then let lifecycle policies act on that tag rather than a timestamp.&lt;/p&gt;

&lt;p&gt;The following AWS S3 lifecycle configuration shows the pattern in practice. It moves objects tagged as archival straight to Glacier after a short staging period, while leaving objects tagged as analytical in Standard-IA, where retrieval is still fast but the storage rate is lower.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ID"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MoveArchivalToGlacier"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Filter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Tag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"access-pattern"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"archival"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Enabled"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Transitions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Days"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"StorageClass"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GLACIER"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ID"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MoveAnalyticalToIA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Filter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Tag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"access-pattern"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"analytical"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Enabled"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Transitions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Days"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"StorageClass"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"STANDARD_IA"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Applying this policy requires the application layer to tag objects correctly at upload time, which is a small discipline that pays off compounding returns as object counts grow into the millions. A single mistagged bucket policy is easy to fix; millions of individually mistagged objects are not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tiering Is a Starting Point, Not a Strategy
&lt;/h2&gt;

&lt;p&gt;Storage tiers (hot, cool, archive) get most of the attention in cost conversations, but tiering alone will not fix a poorly designed system. Google Cloud's regional pricing illustrates the spread: Standard storage runs about $0.020 per GB per month, Nearline drops to roughly $0.010, Coldline to $0.004, and Archive down to about $0.0012 in-region. That is more than a fifteen-fold difference between the top and bottom tier, but the discount only pays off if retrieval patterns actually match the tier chosen. Archive-tier data that gets pulled weekly will cost more in retrieval fees than it saves in storage rate.&lt;/p&gt;

&lt;p&gt;A smarter approach treats tiering as one lever among several: object lifecycle policies, compression before write, deduplication at ingestion, and query-aware partitioning for analytical datasets. AI-driven compression techniques are already cutting effective storage costs by roughly 20% for some workloads, and pairing compression with correct tiering compounds the savings rather than just adding to them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling the New Cost Center: Vector and AI Storage
&lt;/h2&gt;

&lt;p&gt;Vector storage for retrieval-augmented generation and embedding search is now one of the fastest-growing line items on cloud bills, and it behaves differently from traditional object storage. AWS S3 Vectors, for example, prices storage separately from vector upload operations and query charges, with vendors reporting storage costs up to 90% lower than dedicated managed vector &lt;a href="https://it.telkomuniversity.ac.id/peranan-dan-jenis-database-dalam-berbagai-industri-teknologi/" rel="noopener noreferrer"&gt;databases&lt;/a&gt; for comparable workloads. The lesson generalizes beyond any single vendor: purpose-built storage for a specific access pattern usually beats forcing a general-purpose object store to do a specialized job.&lt;/p&gt;

&lt;p&gt;A simple Python helper illustrates how a team might route embeddings to the right backend based on how frequently a given index is queried, keeping hot indexes in a low-latency vector store and archiving cold ones to standard object storage as compressed files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;gzip&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;route_embedding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vector_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query_frequency&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Route embeddings to the storage backend matching their access pattern.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;query_frequency&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Hot path: keep in the managed vector store for low-latency lookups
&lt;/span&gt;        &lt;span class="n"&gt;vector_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upsert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;index_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vectors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vector_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Cold path: compress and archive to object storage
&lt;/span&gt;        &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gzip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vector_data&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;object_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;embeddings-archive&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;index_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.json.gz&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This kind of routing logic is a small piece of code, but it encodes a real architectural decision: not every embedding deserves the same storage economics, and the application layer is the right place to enforce that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building for Resilience Without Overpaying for It
&lt;/h2&gt;

&lt;p&gt;Redundancy and resilience are non-negotiable for production data, but teams frequently over-provision replication out of habit rather than requirement. Synchronous multi-region replication makes sense for a primary transactional database; it rarely makes sense for build artifacts or intermediate ETL output that can be regenerated on demand. Matching replication strategy to actual recovery requirements, rather than defaulting every bucket to the highest available durability setting, is one of the simplest ways to reduce spend without touching data volume at all.&lt;/p&gt;

&lt;p&gt;Surveys of infrastructure teams show that a majority now run hybrid storage models, blending public cloud with private infrastructure specifically to control cost and maintain leverage over vendors. That flexibility only helps if the underlying data is portable, which means avoiding proprietary formats and vendor-specific metadata wherever an open standard exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring Is Part of the Architecture
&lt;/h2&gt;

&lt;p&gt;A smart storage system degrades over time if nobody is watching how it is actually used. Cost anomalies are far cheaper to catch the day they happen than at the end of a billing cycle, when the fix requires re-architecting rather than adjusting a policy. Teams that build cost and access-pattern dashboards alongside their storage layer, not as an afterthought bolted on by finance, catch tier mismatches, orphaned snapshots, and runaway replication before they become a line item worth escalating.&lt;/p&gt;

&lt;p&gt;The practical takeaway is that cloud storage optimization is not a one-time migration project. It is closer to garbage collection: a recurring process of tagging, measuring, and reclaiming, built into the same pipelines that write the data in the first place. Teams that treat it that way spend less time firefighting budget overruns and more time building the systems the data was collected for in the first place.&lt;/p&gt;

&lt;p&gt;If your team is planning a storage architecture refresh, start by auditing access patterns on your largest buckets before touching tier assignments. The savings usually live in the mismatch between how data is stored and how it is actually used, not in switching providers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to Start This Week
&lt;/h2&gt;

&lt;p&gt;Most teams do not need a full re-architecture to see meaningful savings; they need to close the gap between their largest three or four buckets and the access patterns those buckets actually see. Pull a report of object age versus last-accessed timestamp for the biggest storage consumers, and the mismatches tend to surface immediately: months-old logs sitting in a hot tier, or a dataset queried daily that somehow ended up in cold storage during a migration. Fixing those specific buckets first, before writing a single new lifecycle policy elsewhere, usually returns the fastest payback for the least engineering effort.&lt;/p&gt;

&lt;p&gt;The broader shift worth internalizing is that storage decisions are no longer purely an infrastructure concern; they sit right next to product and data-engineering decisions about what gets collected, how long it is kept, and who queries it. Smarter cloud data storage is what happens when those three groups start making that call together instead of leaving it to whichever team owns the cloud bill.&lt;/p&gt;

</description>
      <category>database</category>
      <category>cloud</category>
      <category>devops</category>
    </item>
    <item>
      <title>18 API Project Ideas to Build Your Portfolio in 2026</title>
      <dc:creator>Fu'ad Husnan</dc:creator>
      <pubDate>Sun, 02 Aug 2026 09:04:22 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/18-api-project-ideas-to-build-your-portfolio-in-2026-l98</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/18-api-project-ideas-to-build-your-portfolio-in-2026-l98</guid>
      <description>&lt;p&gt;Finding the right &lt;strong&gt;API project ideas&lt;/strong&gt; is one of the fastest ways to turn a thin resume into a portfolio hiring managers actually stop to read. Building and consuming &lt;a href="https://jakarta.telkomuniversity.ac.id/apa-itu-api-panduan-lengkap-penghubung-antar-aplikasi/" rel="noopener noreferrer"&gt;APIs&lt;/a&gt; proves you understand authentication, data modeling, error handling, and the kind of real-world messiness that tutorials tend to skip. This list covers eighteen projects ranked roughly by difficulty, from weekend builds to systems worth putting at the top of your GitHub profile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why API Projects Move the Needle
&lt;/h2&gt;

&lt;p&gt;A to-do list app tells an employer you can follow instructions. An API project tells them you can design a system. Every API you build forces decisions about status codes, rate limiting, pagination, and versioning — the exact vocabulary that shows up in technical interviews. Consuming third-party APIs adds a second skill: reading documentation, handling flaky responses, and caching data so you're not hammering someone else's server on every page load.&lt;/p&gt;

&lt;p&gt;The projects below split into three buckets: building your own API from scratch, consuming an existing API to create something useful, and full-stack projects that do both. Pick a few from each bucket rather than eighteen shallow clones of the same idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beginner Builds: Your Own First APIs
&lt;/h2&gt;

&lt;p&gt;Start by designing and shipping a REST API before you touch anyone else's data. A personal blog API with endpoints for posts, comments, and tags teaches CRUD operations and basic authentication without much domain complexity. A recipe box API that stores ingredients, steps, and cook times works well because the data model has natural relationships worth practicing on. A habit tracker API, where users log daily check-ins against goals, adds a light analytics layer once you start returning streaks and completion rates.&lt;/p&gt;

&lt;p&gt;Here's a minimal example of what a habit tracker endpoint might look like in Express:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/habits/:id/checkins&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;habit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Habit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;habit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Habit not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Checkin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;habitId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;streak&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;calculateStreak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;checkin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;currentStreak&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;streak&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A URL shortener rounds out this tier. It looks simple, but doing it properly means handling collisions in your short-code generator, redirect status codes, and basic click analytics — all good interview talking points.&lt;/p&gt;

&lt;h2&gt;
  
  
  Intermediate Builds: Adding Real Constraints
&lt;/h2&gt;

&lt;p&gt;Once the basics are solid, move to projects that force you to handle authentication properly and think about scale. A job board API with employer and candidate roles introduces permission-based access control, since employers and applicants shouldn't see the same endpoints. An expense tracker API with multi-currency support pushes you into third-party integration territory, since you'll likely pull live exchange rates from an external service and cache them sensibly.&lt;/p&gt;

&lt;p&gt;A note-taking API with full-text search is a good one for learning database indexing, particularly if you implement it against PostgreSQL's built-in search rather than reaching for Elasticsearch immediately. An event booking API with seat or slot reservations teaches you about race conditions: two people trying to book the same slot at the same time is a classic concurrency problem worth solving with database-level locking or optimistic concurrency checks.&lt;/p&gt;

&lt;p&gt;A rate-limited public API is worth building even if the underlying data is simple, because implementing your own rate limiter — whether token bucket or sliding window — is a concept that comes up constantly in system design interviews. Pairing it with API key issuance and basic usage dashboards makes the project feel like a real product rather than an exercise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consuming Third-Party APIs: Client-Side Skill Building
&lt;/h2&gt;

&lt;p&gt;Building your own API is half the picture; consuming someone else's is the other half, and it's the half that mirrors most day-to-day engineering work. A weather dashboard that pulls from a free weather API and layers in caching, error states, and graceful degradation when the upstream service is slow teaches resilience patterns beyond the basic fetch call. A GitHub activity visualizer that pulls a user's commit history and renders it as a contribution-style chart is a great portfolio piece because it's visual, personal, and easy for reviewers to try with their own username.&lt;/p&gt;

&lt;p&gt;A currency converter that compares rates across two or three providers and flags discrepancies goes a step further than a simple wrapper, since it requires normalizing inconsistent response formats. A movie or book recommendation tool built on a public media API, with your own filtering logic layered on top, shows you can add value rather than just re-displaying someone else's data.&lt;/p&gt;

&lt;p&gt;A simple example of defensive API consumption, handling timeouts and retries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;requests.exceptions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Timeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RequestException&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_weather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;retries&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;retries&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.weatherprovider.com/v1/current&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;city&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;Timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;RequestException&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Weather fetch failed: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Full-Stack Projects: Build and Consume Together
&lt;/h2&gt;

&lt;p&gt;The strongest portfolio pieces usually combine both skills. A social media scheduler that lets users draft posts and queue them for publishing through a platform's API demonstrates OAuth flows, background job scheduling, and webhook handling in one project. A price-tracking tool that scrapes or polls product listings and notifies users via email or webhook when a price drops teaches you to build both the polling API and the notification pipeline.&lt;/p&gt;

&lt;p&gt;A fitness aggregator that pulls data from a wearable device API and your own custom API for goals and notes shows you can merge external and internal data sources into one coherent view. A podcast or newsletter aggregator that indexes RSS feeds through your own API layer, with search and filtering on top, is deceptively rich: RSS parsing has enough edge cases (malformed XML, inconsistent date formats) that it tests your error handling under real conditions.&lt;/p&gt;

&lt;p&gt;A collaborative API-first project management tool, where the API is the actual product rather than a backend detail, is worth attempting if you want to demonstrate API design as a first-class skill: versioning strategy, OpenAPI documentation, and webhook support for third-party integrations. A chatbot or support-ticket router that classifies incoming messages using a language model API and routes them to the right internal endpoint shows you can integrate AI services into a traditional API architecture without over-engineering it.&lt;/p&gt;

&lt;p&gt;Finally, a personal finance dashboard that aggregates data from a banking API, a budgeting API you build yourself, and a currency API rounds out the list. It's ambitious enough to show systems thinking, but scoped enough to finish in a few weeks if you limit the number of accounts and categories you support at launch.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Choose Which Ones to Build
&lt;/h2&gt;

&lt;p&gt;Don't build all eighteen. Pick two or three that align with the roles you're applying for. If you're targeting backend roles, weight your selection toward the API-building projects and document your database schema decisions in the README. If you're targeting full-stack or frontend roles, lean into the consuming-API projects and put more effort into the interface, since that's what a hiring manager will actually click through.&lt;/p&gt;

&lt;p&gt;Whichever you choose, treat documentation as part of the deliverable, not an afterthought. A short README explaining the endpoints, the reasoning behind your data model, and one or two tradeoffs you made says more about your engineering judgment than the code itself ever will.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turning These Projects Into Interview Material
&lt;/h2&gt;

&lt;p&gt;Every project on this list has a natural interview question buried in it. Rate limiting invites a system design discussion. Concurrent booking invites a database locking discussion. Third-party API failures invite a resilience and monitoring discussion. Before you call a project "done," write down the one or two hard decisions you made while building it — that's the story you'll actually tell in an interview, and it's worth more than the finished demo link.&lt;/p&gt;

&lt;p&gt;Start with one project this week. Ship it, document it, and only then move to the next. A portfolio of three finished, well-documented APIs will always beat eighteen half-built repos sitting untouched since their first commit.&lt;/p&gt;

</description>
      <category>api</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
