<?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: wennan xu</title>
    <description>The latest articles on DEV Community by wennan xu (@wennan_xu).</description>
    <link>https://dev.to/wennan_xu</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2207862%2Face84a89-f3a9-4be7-9e45-8e98900065ba.png</url>
      <title>DEV Community: wennan xu</title>
      <link>https://dev.to/wennan_xu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wennan_xu"/>
    <language>en</language>
    <item>
      <title>Monilith vs Monorepo</title>
      <dc:creator>wennan xu</dc:creator>
      <pubDate>Sun, 28 Sep 2025 05:15:09 +0000</pubDate>
      <link>https://dev.to/wennan_xu/monilith-vs-monorepo-3309</link>
      <guid>https://dev.to/wennan_xu/monilith-vs-monorepo-3309</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8mzm882ciw1p9by7hon7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8mzm882ciw1p9by7hon7.png" alt=" " width="800" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Thread safe strategy in Java or .net</title>
      <dc:creator>wennan xu</dc:creator>
      <pubDate>Mon, 15 Sep 2025 11:25:56 +0000</pubDate>
      <link>https://dev.to/wennan_xu/thread-safe-strategy-in-java-or-net-2jb9</link>
      <guid>https://dev.to/wennan_xu/thread-safe-strategy-in-java-or-net-2jb9</guid>
      <description>&lt;h2&gt;
  
  
  Stateless design
&lt;/h2&gt;

&lt;p&gt;Just like in Java, designing classes without shared mutable state is the safest approach.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class MyProcessor
{
    public string Process(string input)
    {
        return input.ToUpper(); // No shared state
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ThreadLocal
&lt;/h2&gt;

&lt;p&gt;ThreadLocal is a .NET class that allows you to store data that is local to a specific thread. Each thread accessing a ThreadLocal instance gets its own independent copy of the data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private static ThreadLocal&amp;lt;Random&amp;gt; random = new ThreadLocal&amp;lt;Random&amp;gt;(() =&amp;gt; new Random());

public int GetRandomNumber()
{
    return random.Value.Next();
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Synchronized blocks
&lt;/h2&gt;

&lt;p&gt;Use lock (or Monitor) to protect shared resources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private readonly object _lock = new object();
private List&amp;lt;string&amp;gt; _sharedList = new List&amp;lt;string&amp;gt;();

public void AddItems(List&amp;lt;string&amp;gt; items)
{
    lock (_lock)
    {
        _sharedList.AddRange(items);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ReentrantLock — More powerful, flexible locking with timeout
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ReentrantLock lock = new ReentrantLock();

try {

    acquired = lock.tryLock(500, TimeUnit.MILLISECONDS);
    if (acquired) {
        System.out.println("Lock acquired, doing work...");
        // critical section
        Thread.sleep(1000); // simulate work
    } else {
        System.out.println("Could not acquire lock within timeout.");
    }
} finally {
    lock.unlock();
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ReentrantReadWriteLock — More powerful and more flexible, providing two locks - readLock and writelock with timeout, Effect: Multiple threads can read concurrently. Only one thread can write, and it blocks all readers.
&lt;/h2&gt;

&lt;p&gt;Concurrency: Much better for read-heavy workloads.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
private final Lock writeLock = rwLock.writeLock();

public String read(String key) {
    readLock.lock();
    try {
        return sharedMap.get(key);
    } finally {
        readLock.unlock();
    }
}

public void write(String key, String value) {
    writeLock.lock();
    try {
        sharedMap.put(key, value);
    } finally {
        writeLock.unlock();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Thread-safe collections
&lt;/h2&gt;

&lt;p&gt;Thread-safe collections are designed to handle concurrent access without requiring manual locking.&lt;br&gt;
Common Thread-Safe Collections in .NET&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Collection               Use Case
ConcurrentDictionary    Key-value store with safe concurrent access
ConcurrentQueue         FIFO queue for producer-consumer scenarios
ConcurrentStack         LIFO stack for concurrent access
ConcurrentBag           Unordered collection for fast insert/retrieve
BlockingCollection  Thread-safe wrapper for producer-consumer with blocking and bounding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Partitioning
&lt;/h2&gt;

&lt;p&gt;Similar to Spring Batch partitioning, you can divide work into chunks and assign each to a separate thread or task.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Parallel.ForEach(partitions, partition =&amp;gt;
{
    ProcessPartition(partition);
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Immutable data
&lt;/h2&gt;

&lt;p&gt;Immutable types are inherently thread-safe. You can use records or readonly structs in C#.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public record Person(string Name, int Age);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>designpatterns</category>
      <category>architecture</category>
    </item>
    <item>
      <title>OWASP Top 10 2025</title>
      <dc:creator>wennan xu</dc:creator>
      <pubDate>Mon, 15 Sep 2025 03:12:02 +0000</pubDate>
      <link>https://dev.to/wennan_xu/owasp-top-10-2025-50l7</link>
      <guid>https://dev.to/wennan_xu/owasp-top-10-2025-50l7</guid>
      <description>&lt;h2&gt;
  
  
  A01:2025 – Broken Access Control
&lt;/h2&gt;

&lt;p&gt;Access control flaws occur when users are allowed to perform actions outside their permission scope, such as accessing another user’s data or modifying records.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implement role-based access control (RBAC) to ensure users only have access to the data and functions they need.&lt;/li&gt;
&lt;li&gt;Regularly audit user permissions to remove unnecessary privileges.&lt;/li&gt;
&lt;li&gt;Enforce multi-factor authentication (MFA) for critical operations to add an additional layer of security.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A02:2025 – Injection attacks, particularly SQL injection
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Always sanitize and validate user inputs to prevent the execution of untrusted commands.&lt;/li&gt;
&lt;li&gt;Use parameterized queries or prepared statements to safely process database inputs.&lt;/li&gt;
&lt;li&gt;Implement Web Application Firewalls (WAF) to detect and block injection attempts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A03:2025 – Insecure Design (Combined with Security Logging and Monitoring Failures)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Adopt threat modeling early in the development cycle to identify potential security risks.&lt;/li&gt;
&lt;li&gt;Use security frameworks and libraries that enforce secure design principles.&lt;/li&gt;
&lt;li&gt;Ensure all critical systems have comprehensive logging in place.&lt;/li&gt;
&lt;li&gt;Use real-time monitoring tools to detect unusual activity.&lt;/li&gt;
&lt;li&gt;Regularly audit logs to ensure compliance with security policies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A04:2025 – Identification and Authentication Failures
&lt;/h2&gt;

&lt;p&gt;Authentication failures can lead to severe security breaches, allowing attackers to impersonate legitimate users. This vulnerability includes weak passwords, missing multifactor authentication (MFA), and flawed session management.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enforce strong password policies with minimum complexity requirements.&lt;/li&gt;
&lt;li&gt;Implement multifactor authentication (MFA) to add an additional layer of protection.&lt;/li&gt;
&lt;li&gt;Use secure, industry-standard session management techniques, including secure tokens and cookies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A05:2025 – Cryptographic Failures
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use strong encryption algorithms such as AES-256 and ensure proper key management.&lt;/li&gt;
&lt;li&gt;Avoid outdated cryptographic methods like MD5 or SHA-1, as they are prone to attacks.&lt;/li&gt;
&lt;li&gt;Regularly update and patch encryption libraries to safeguard against newly discovered vulnerabilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A06:2025 – Security Misconfiguration
&lt;/h2&gt;

&lt;p&gt;Security misconfigurations occur when default settings, incomplete configurations, or errors in security settings leave applications vulnerable to attack. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Regularly audit and harden configurations to meet industry security standards.&lt;/li&gt;
&lt;li&gt;Disable unused features and services to reduce the attack surface.&lt;/li&gt;
&lt;li&gt;Use automated configuration management tools to ensure consistency across environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A07:2025 – Vulnerable and Outdated Components
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use automated tools such as Dependabot or Snyk to monitor and update third-party components.&lt;/li&gt;
&lt;li&gt;Regularly review and update dependencies to ensure they are secure.&lt;/li&gt;
&lt;li&gt;Employ software composition analysis (SCA) tools to identify and mitigate risks in your application’s dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A08:2025 – Software and Data Integrity Failures
&lt;/h2&gt;

&lt;p&gt;This vulnerability occurs when software updates, critical data, or infrastructure components are not properly secured, leading to unauthorized changes that compromise system integrity.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sign and verify software updates to ensure their integrity.&lt;/li&gt;
&lt;li&gt;Implement integrity checks on critical data to detect tampering.&lt;/li&gt;
&lt;li&gt;Regularly monitor and verify the integrity of infrastructure components.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Server-Side Request Forgery (SSRF): The Emerging Threat
&lt;/h2&gt;

&lt;p&gt;SSRF vulnerabilities occur when an attacker can manipulate a server to send unauthorized requests to other systems, potentially bypassing firewalls and exposing sensitive data. As microservices and cloud applications become more prevalent, SSRF is becoming a growing concern.&lt;/p&gt;

&lt;p&gt;Real-World Impact:&lt;/p&gt;

&lt;p&gt;In 2021, an SSRF vulnerability in Microsoft Azure exposed sensitive internal information, highlighting the growing risks of this attack vector in cloud environments.&lt;/p&gt;

&lt;p&gt;Mitigation Strategies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implement input validation to prevent attackers from injecting malicious URLs.&lt;/li&gt;
&lt;li&gt;Restrict outbound network access to limit the scope of SSRF attacks.&lt;/li&gt;
&lt;li&gt;Use firewalls and network segmentation to protect critical systems from unauthorized requests.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How to use pgpainless-core</title>
      <dc:creator>wennan xu</dc:creator>
      <pubDate>Sun, 09 Mar 2025 00:02:38 +0000</pubDate>
      <link>https://dev.to/wennan_xu/how-to-use-pgpainless-core-2amn</link>
      <guid>https://dev.to/wennan_xu/how-to-use-pgpainless-core-2amn</guid>
      <description>&lt;h2&gt;
  
  
  Document
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://pgpainless.readthedocs.io/en/latest/quickstart.html" rel="noopener noreferrer"&gt;https://pgpainless.readthedocs.io/en/latest/quickstart.html&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// If you use Gradle
...
dependencies {
    ...
    implementation "org.pgpainless:pgpainless-core:1.7.2"
    ...
}

// If you use Maven
...
&amp;lt;dependencies&amp;gt;
    ...
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;org.pgpainless&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;pgpainless-core&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;1.7.2&amp;lt;/version&amp;gt;
    &amp;lt;/dependency&amp;gt;
    ...
&amp;lt;/dependencies&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's ASCII Armor
&lt;/h2&gt;

&lt;p&gt;ASCII armor is a layer of radix64 encoding that can be used to wrap binary OpenPGP data in order to make it save to transport via text-based channels (e.g. email bodies).&lt;/p&gt;

&lt;p&gt;The way in which ASCII armor can be applied depends on the type of data that you want to protect. The easies way to ASCII armor an OpenPGP key or certificate is by using PGPainless’ asciiArmor() method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PGPPublicKey certificate = ...;
String asciiArmored = PGPainless.asciiArmor(certificate);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to Setup the ProducerOptions when Encrypt
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Suppose you have a &lt;code&gt;FileInputStream&lt;/code&gt; or &lt;code&gt;ByteArrayInputStream&lt;/code&gt;. Then
also you need to have a &lt;code&gt;OutputStream&lt;/code&gt;, like
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OutputStream outputStream =
                        Files.newOutputStream(outputFileLocation, StandardOpenOption.CREATE_NEW);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Before you call the &lt;code&gt;Painless.encryptAndOrSign()&lt;/code&gt;, you need to build up the &lt;code&gt;ProducerOptions&lt;/code&gt;. It will be like
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/** The secret key ring used for decrypting and signing. */
private final PGPSecretKeyRing secretKeyRing = ...;

/** The public key ring used for encrypting. */
private final PGPPublicKeyRing publicKeyRing = ...;

/** Stores the password securely, required to access the secret key. */
private final SecretKeyRingProtector secretKeyRingProtector = ...;

SigningOptions signOptions = SigningOptions.get().addInlineSignature(secretKeyRingProtector, secretKeyRing);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;when you try to build your &lt;code&gt;secretKeyRing&lt;/code&gt; and &lt;code&gt;secretKeyRingProtector&lt;/code&gt;, you probably will get it from your properties like
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this.secretKeyRing = armorStringKeyringLoader.load(properties.getSecretKey(), PGPSecretKeyRing.class)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this.publicKeyRing = armorStringKeyringLoader.load(properties.getPublicKey(), PGPPublicKeyRing.class)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to load the key, all you need to do is to get the BufferedInputStream, then&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;protected &amp;lt;T extends PGPKeyRing&amp;gt; T readKeyRing(BufferedInputStream keyInputStream, Class&amp;lt;T&amp;gt; clazz) throws IOException, KeyRingLoaderException {
    if (clazz.isAssignableFrom(PGPSecretKeyRing.class)) {
        return clazz.cast(PGPainless.readKeyRing().secretKeyRing(keyInputStream));
    } else if (clazz.isAssignableFrom(PGPPublicKeyRing.class)) {
        return clazz.cast(PGPainless.readKeyRing().publicKeyRing(keyInputStream));
    } throw new KeyRingLoaderException(
        String.format("Unsupported key ring type [class=%s]", clazz.getSimpleName()));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create that BufferedInputStream from string can be like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public BufferedInputStream getBufferedInputStreamForKey(String armorKey) throws Exception {
        // return a new BufferedInputStream with the key as the content.
        ByteSource byteSource = ByteSource.wrap(armorKey.getBytes());
        return new BufferedInputStream(byteSource.openStream());
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or create that BufferedInputStream from file can be like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public BufferedInputStream getBufferedInputStreamForKey(String armorKeyfileLocation) throws IOException {
    // Loads the ascii armor key file from the file system.
    return (BufferedInputStream) Files.asByteSource(new File(armorKeyfileLocation)).openBufferedStream();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now lets build the encryptionOptions. You only need to add the recipient's public key as the
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PGPPublicKey certificate = ...;
EncryptionOptions encOptions = EncryptionOptions.get().addRecipient(certificate);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same philosophy to load the PGPPublicKey via &lt;code&gt;PGPainless.readKeyRing().publicKeyRing(keyInputStream)&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;So now we can put both of them into the  &lt;code&gt;ProducerOptions options&lt;/code&gt; like
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ProducerOptions options = ProducerOptions.signAndEncrypt(signingOptions, encryptionOptions);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to ASCII armor ciphertext, you can enable ASCII armoring during encrypting/signing by requesting PGPainless to armor the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;producerOptions.setAsciiArmor(true); // enable armoring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;File Association: When you encrypt data, you might want to include the original file name so that the recipient knows what the encrypted content represents. The setFileName method allows you to set this file name.&lt;br&gt;
Metadata: Including the file name as metadata can help the recipient understand the context of the encrypted data, especially if multiple files are being encrypted and sent together. So you can do like:&lt;br&gt;
&lt;code&gt;producerOptions.setFileName(outputFileLocation.toString())&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Encrypt with the OutputStream
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EncryptionStream encryptionStream = PGPainless.encryptAndOrSign()
        .onOutputStream(outputStream)
        .withOptions(producerOptions);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Encrypt the file data
&lt;/h2&gt;

&lt;p&gt;If you already have an existing file, you can encrypt it to another file location like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;InputStream plaintext = ...; // The data that will be encrypted and/or signed
ByteArrayInputStream contentToEncrypt = ...; // can also be the ByteArrayInputStream 
OutputStream ciphertext = Files.newOutputStream(Path outputFileLocation, StandardOpenOption.CREATE_NEW); // Destination for the ciphertext

EncryptionStream encryptionStream = PGPainless.encryptAndOrSign()
        .onOutputStream(ciphertext)
        .withOptions(producerOptions); // pass in the options object

Streams.pipeAll(plaintext, encryptionStream); // pipe the data through
encryptionStream.close(); // important! Close the stream to finish encryption/signing

EncryptionResult result = encryptionStream.getResult(); // metadata
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Use the EncryptionStream in Spring batch OutputStreamWriter.
&lt;/h2&gt;

&lt;p&gt;As EncryptionStream is also a sub-class of OutputStream, so we can wrap it  into the Spring batch writer like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new OutputStreamWriter(EncryptionStream, StandardCharsets.UTF_8);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So now we will get a Encrypted output stream, we can write the encrypted data into the output stream in Spring batch.  &lt;/p&gt;

&lt;h2&gt;
  
  
  How to Setup the ConsumerOptions when Decrypt
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new ConsumerOptions()
.addDecryptionKey(SecretKeyRing, SecretKeyRingProtector)
.addVerificationCert(PublicKeyRing)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Build the DecryptionStream
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// this is the file we are going to decrypt
InputStream inputStream = Files.newInputStream(inputFileLocation, StandardOpenOption.CREATE_NEW);

DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify()
    .onInputStream(inputStream)
    .withOptions(ConsumerOptions)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Reuse this DecryptionStream in Spring batch reader
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new InputStreamWriter(decryptionStream, StandardCharsets.UTF_8);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Decrypt the file
&lt;/h2&gt;

&lt;p&gt;if you have an existing encrypted file, and you want to decrypt it to another file location. You can initialize the ByteArrayOutputStream which will receive the decrypted data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ByteArrayOutputStream decryptedContentOutput;
Streams.pipeAll(decryptionStream, decryptedContentOutput);
// must close before we can get the metadata.
decryptionStream.close();
MessageMetadata messageMetadata = decryptionStream.getMetadata();
logCompleted(messageMetadata, inputFileLocation);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>encryption</category>
      <category>decryption</category>
    </item>
    <item>
      <title>SameSite cookies and CSRF explained</title>
      <dc:creator>wennan xu</dc:creator>
      <pubDate>Mon, 14 Oct 2024 06:15:42 +0000</pubDate>
      <link>https://dev.to/wennan_xu/samesite-cookies-and-csrf-explained-1oip</link>
      <guid>https://dev.to/wennan_xu/samesite-cookies-and-csrf-explained-1oip</guid>
      <description>&lt;p&gt;We might normally heard the terms of &lt;code&gt;SameSite&lt;/code&gt; and &lt;code&gt;CSRF&lt;/code&gt;, What are they on the earth, and what's the relationship between them?&lt;/p&gt;

&lt;h2&gt;
  
  
  What is HTTP cookies
&lt;/h2&gt;

&lt;p&gt;A cookie (also known as a web cookie or browser cookie) is a small piece of data a server sends to a user's web browser. The browser may store cookies, create new cookies, modify existing ones, and send them back to the same server with later requests. Cookies enable web applications to store limited amounts of data and remember state information; by default the HTTP protocol is stateless.&lt;br&gt;
Typically, the server will use the contents of HTTP cookies to determine whether different requests come from the same browser/user and then issue a personalized or generic response as appropriate.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user sends sign-in credentials to the server, for example via a form submission.&lt;/li&gt;
&lt;li&gt;If the credentials are correct, the server updates the UI to indicate that the user is signed in, and responds with a cookie containing a session ID that records their sign-in status on the browser.&lt;/li&gt;
&lt;li&gt;At a later time, the user moves to a different page on the same site. The browser sends the cookie containing the session ID along with the corresponding request to indicate that it still thinks the user is signed in.&lt;/li&gt;
&lt;li&gt;The server checks the session ID and, if it is still valid, sends the user a personalized version of the new page. If it is not valid, the session ID is deleted and the user is shown a generic version of the page (or perhaps shown an "access denied" message and asked to sign in again).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpqwjcljiqhgw9t1yd95.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpqwjcljiqhgw9t1yd95.png" alt="Image description" width="800" height="531"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What is a site in the context of SameSite cookies?
&lt;/h2&gt;

&lt;p&gt;Firstly we need to understand what is same site and what is same origin. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frhpaml5xgef5ozvkzhys.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frhpaml5xgef5ozvkzhys.png" alt="Image description" width="800" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
            &lt;tbody&gt;
&lt;tr&gt;
                &lt;td&gt;
                    &lt;strong&gt;Request from&lt;/strong&gt;
                &lt;/td&gt;
                &lt;td&gt;
                    &lt;strong&gt;Request to&lt;/strong&gt;
                &lt;/td&gt;
                &lt;td&gt;
                    &lt;strong&gt;Same-site?&lt;/strong&gt;
                &lt;/td&gt;
                &lt;td&gt;
                    &lt;strong&gt;Same-origin?&lt;/strong&gt;
                &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    &lt;code&gt;https://example.com&lt;/code&gt;
                &lt;/td&gt;
                &lt;td&gt;
                    &lt;code&gt;https://example.com&lt;/code&gt;
                &lt;/td&gt;
                &lt;td&gt;
                    Yes
                &lt;/td&gt;
                &lt;td&gt;
                    Yes
                &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    &lt;code&gt;https://app.example.com&lt;/code&gt;
                &lt;/td&gt;
                &lt;td&gt;
                    &lt;code&gt;https://intranet.example.com&lt;/code&gt;
                &lt;/td&gt;
                &lt;td&gt;
                    Yes
                &lt;/td&gt;
                &lt;td&gt;
                    No: mismatched domain name
                &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    &lt;code&gt;https://example.com&lt;/code&gt;
                &lt;/td&gt;
                &lt;td&gt;
                    &lt;code&gt;https://example.com:8080&lt;/code&gt;
                &lt;/td&gt;
                &lt;td&gt;
                    Yes
                &lt;/td&gt;
                &lt;td&gt;
                    No: mismatched port
                &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    &lt;code&gt;https://example.com&lt;/code&gt;
                &lt;/td&gt;
                &lt;td&gt;
                    &lt;code&gt;https://example.co.uk&lt;/code&gt;
                &lt;/td&gt;
                &lt;td&gt;
                    No: mismatched eTLD
                &lt;/td&gt;
                &lt;td&gt;
                    No: mismatched domain name
                &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    &lt;code&gt;https://example.com&lt;/code&gt;
                &lt;/td&gt;
                &lt;td&gt;
                    &lt;code&gt;http://example.com&lt;/code&gt;
                &lt;/td&gt;
                &lt;td&gt;
                    No: mismatched scheme
                &lt;/td&gt;
                &lt;td&gt;
                    No: mismatched scheme
                &lt;/td&gt;
            &lt;/tr&gt;
        &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  How does SameSite work?
&lt;/h2&gt;

&lt;p&gt;All major browsers currently support the following SameSite restriction levels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strict&lt;/strong&gt;：If a cookie is set with the SameSite=Strict attribute, browsers will not send it in any cross-site requests. This is recommended when setting cookies that enable the bearer to modify data or perform other sensitive actions, such as accessing specific pages that are only available to authenticated users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Although this is the most secure option, it can negatively impact the user experience in cases where cross-site functionality is desirable.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lax&lt;/strong&gt;：Lax SameSite restrictions mean that browsers will send the cookie in cross-site requests, but only if both of the following conditions are met:

&lt;ul&gt;
&lt;li&gt;The request uses the GET method.&lt;/li&gt;
&lt;li&gt;The request resulted from a top-level navigation by the user, such as clicking on a link.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;p&amp;gt;Look at this amazing cat!&amp;lt;/p&amp;gt;
&amp;lt;img src="https://blog.example/blog/img/amazing-cat.png" /&amp;gt;
&amp;lt;p&amp;gt;Read the &amp;lt;a href="https://blog.example/blog/cat.html"&amp;gt;article&amp;lt;/a&amp;gt;.&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;With a cookie set to Lax as follows: &lt;code&gt;Set-Cookie: promo_shown=1; SameSite=Lax&lt;/code&gt;&lt;br&gt;
When the browser requests &lt;code&gt;amazing-cat.png&lt;/code&gt; for the other person's blog, your site doesn't send the cookie. However, when the reader follows the link to &lt;code&gt;cat.html&lt;/code&gt; on your site, that request does include the cookie.&lt;/p&gt;

&lt;p&gt;We recommend using SameSite in this way, setting cookies that affect website display to Lax, and cookies related to user actions to Strict.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;None&lt;/strong&gt;：If a cookie is set with the &lt;code&gt;SameSite=None&lt;/code&gt; attribute, this effectively disables SameSite restrictions altogether, regardless of the browser. As a result, browsers will send this cookie in all requests to the site that issued it, even those that were triggered by completely unrelated third-party sites. When you create cross-site cookies using SameSite=None, you must also set them to Secure for the browser to accept them: &lt;code&gt;Set-Cookie: widget_session=abc123; SameSite=None; Secure&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Bypassing SameSite Lax restrictions using GET requests
&lt;/h2&gt;

&lt;p&gt;As long as the request involves a top-level navigation, the browser will still include the victim's session cookie. The following is one of the simplest approaches to launching such an attack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
    document.location = 'https://vulnerable-website.com/account/transfer-payment?recipient=hacker&amp;amp;amount=1000000';
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even if an ordinary GET request isn't allowed, some frameworks provide ways of overriding the method specified in the request line. For example, Symfony supports the _method parameter in forms, which takes precedence over the normal method for routing purposes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;form action="https://vulnerable-website.com/account/transfer-payment" method="POST"&amp;gt;
    &amp;lt;input type="hidden" name="_method" value="GET"&amp;gt;
    &amp;lt;input type="hidden" name="recipient" value="hacker"&amp;gt;
    &amp;lt;input type="hidden" name="amount" value="1000000"&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;see we can put &lt;code&gt;&amp;lt;input type="hidden" name="_method" value="GET"&amp;gt;&lt;/code&gt; in forms to override the override the original &lt;code&gt;POST&lt;/code&gt; request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bypassing SameSite restrictions using on-site gadgets
&lt;/h2&gt;

&lt;p&gt;One possible gadget is a client-side redirect that dynamically constructs the redirection target using attacker-controllable input like URL parameters. For some examples, see our materials on &lt;a href="https://portswigger.net/web-security/dom-based/open-redirection" rel="noopener noreferrer"&gt;DOM-based open redirection&lt;/a&gt;.&lt;br&gt;
DOM-based open-redirection vulnerabilities arise when a script writes attacker-controllable data into a sink that can trigger cross-domain navigation. For example, the following code is vulnerable due to the unsafe way it handles the location.hash property:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let url = /https?:\/\/.+/.exec(location.hash);
if (url) {
  location = url[0];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An attacker may be able to use this vulnerability to construct a URL that, if visited by another user, will cause a redirection to an arbitrary external domain.&lt;br&gt;
As far as browsers are concerned, these client-side redirects aren't really redirects at all; the resulting request is just treated as an ordinary, standalone request. Most importantly, this is a same-site request and, as such, will include all cookies related to the site, regardless of any restrictions that are in place.&lt;br&gt;
How to prevent DOM-based open-redirection vulnerabilities, you should avoid dynamically setting redirection targets using data that originated from any untrusted source.&lt;/p&gt;
&lt;h2&gt;
  
  
  Bypassing SameSite Lax restrictions with newly issued cookies
&lt;/h2&gt;

&lt;p&gt;Cookies with Lax SameSite restrictions aren't normally sent in any cross-site POST requests, but there are some exceptions.&lt;/p&gt;

&lt;p&gt;As mentioned earlier, if a website doesn't include a SameSite attribute when setting a cookie, Chrome automatically applies Lax restrictions by default. However, to avoid breaking single sign-on (SSO) mechanisms, it doesn't actually enforce these restrictions for the first 120 seconds on top-level POST requests. As a result, there is a two-minute window in which users may be susceptible to cross-site attacks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Note
This two-minute window does not apply to cookies that were explicitly set with the SameSite=Lax attribute.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;:&lt;br&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies&lt;/a&gt;&lt;br&gt;
&lt;a href="https://portswigger.net/web-security/csrf/bypassing-samesite-restrictions" rel="noopener noreferrer"&gt;https://portswigger.net/web-security/csrf/bypassing-samesite-restrictions&lt;/a&gt;&lt;br&gt;
&lt;a href="https://web.dev/articles/samesite-cookies-explained" rel="noopener noreferrer"&gt;https://web.dev/articles/samesite-cookies-explained&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
