<?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: Ian McMurray</title>
    <description>The latest articles on DEV Community by Ian McMurray (@imcmurray).</description>
    <link>https://dev.to/imcmurray</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%2F3784519%2Ff21c307c-4073-4982-a60f-ef69f808b291.png</url>
      <title>DEV Community: Ian McMurray</title>
      <link>https://dev.to/imcmurray</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/imcmurray"/>
    <language>en</language>
    <item>
      <title>How to Check If Your Website Has SPF and DMARC Records (And Why Email Security Matters)</title>
      <dc:creator>Ian McMurray</dc:creator>
      <pubDate>Wed, 25 Feb 2026 06:16:29 +0000</pubDate>
      <link>https://dev.to/imcmurray/how-to-check-if-your-website-has-spf-and-dmarc-records-and-why-email-security-matters-18pm</link>
      <guid>https://dev.to/imcmurray/how-to-check-if-your-website-has-spf-and-dmarc-records-and-why-email-security-matters-18pm</guid>
      <description>&lt;p&gt;Someone is probably sending email from your domain right now. Not you -- someone pretending to be you.&lt;/p&gt;

&lt;p&gt;Without SPF and DMARC records, anyone can send an email that looks like it came from &lt;code&gt;yourcompany.com&lt;/code&gt;. Phishing attacks, fake invoices, password reset scams -- all using your domain name, all landing in your customers' inboxes.&lt;/p&gt;

&lt;p&gt;The fix takes five minutes. Here's how to check if you're protected, and what to do if you're not.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are SPF and DMARC?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SPF (Sender Policy Framework)
&lt;/h3&gt;

&lt;p&gt;SPF is a DNS record that says "these servers are allowed to send email for my domain." When someone receives an email claiming to be from your domain, their mail server checks your SPF record. If the sending server isn't on the list, the email gets flagged or rejected.&lt;/p&gt;

&lt;p&gt;An SPF record looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v=spf1 include:_spf.google.com include:sendgrid.net -all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This says: Google and SendGrid can send email for us. Everyone else should be rejected (&lt;code&gt;-all&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  DMARC (Domain-based Message Authentication, Reporting &amp;amp; Conformance)
&lt;/h3&gt;

&lt;p&gt;DMARC builds on SPF (and DKIM) to tell receiving mail servers what to do when authentication fails. Without DMARC, a failing SPF check might still get delivered -- the receiving server doesn't know how strict you want to be.&lt;/p&gt;

&lt;p&gt;A DMARC record looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v=DMARC1; p=reject; rua=mailto:dmarc-reports@yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This says: if an email fails authentication, reject it. And send us reports about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters Even If You Don't Send Email
&lt;/h2&gt;

&lt;p&gt;Here's the part most people miss: &lt;strong&gt;you need SPF and DMARC even if your domain doesn't send email.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;yourdomain.com&lt;/code&gt; has no SPF record, an attacker can send emails as &lt;code&gt;ceo@yourdomain.com&lt;/code&gt; and nothing will stop them. The receiving mail server has no way to know those emails aren't legitimate.&lt;/p&gt;

&lt;p&gt;For domains that don't send email, you still want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v=spf1 -all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This explicitly says "no server is authorized to send email for this domain." It's a one-line fix that blocks an entire category of attacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Check Your Records
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Quick Way
&lt;/h3&gt;

&lt;p&gt;Scan your domain with &lt;a href="https://guardscan.dev" rel="noopener noreferrer"&gt;GuardScan&lt;/a&gt;. It checks SPF, DMARC, and DNSSEC as part of a full security scan, and shows you the actual record values.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Command-Line Way
&lt;/h3&gt;

&lt;p&gt;Check your SPF record:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dig +short TXT yourdomain.com | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"v=spf1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check your DMARC record:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dig +short TXT _dmarc.yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If either command returns nothing, you're missing that record.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Good Results Look Like
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;SPF present and valid:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"v=spf1 include:_spf.google.com ~all"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;DMARC present with enforcement:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.com"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What Bad Results Look Like
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;No SPF record:&lt;/strong&gt; The &lt;code&gt;dig&lt;/code&gt; command returns nothing. Anyone can send email as your domain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SPF with &lt;code&gt;+all&lt;/code&gt;:&lt;/strong&gt; This explicitly allows every server on the internet to send email as you. It's worse than having no record at all, because it looks intentional.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DMARC with &lt;code&gt;p=none&lt;/code&gt;:&lt;/strong&gt; The record exists but does nothing. It's monitoring mode -- useful temporarily while you're setting up, but not a real defense. Failed emails still get delivered.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Add SPF and DMARC Records
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Figure Out Who Sends Email for You
&lt;/h3&gt;

&lt;p&gt;Before you add an SPF record, list every service that sends email using your domain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google Workspace&lt;/strong&gt; -- &lt;code&gt;include:_spf.google.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Microsoft 365&lt;/strong&gt; -- &lt;code&gt;include:spf.protection.outlook.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SendGrid&lt;/strong&gt; -- &lt;code&gt;include:sendgrid.net&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mailchimp&lt;/strong&gt; -- &lt;code&gt;include:servers.mcsv.net&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amazon SES&lt;/strong&gt; -- &lt;code&gt;include:amazonses.com&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check your current email provider's documentation for their specific SPF include.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Create Your SPF Record
&lt;/h3&gt;

&lt;p&gt;Add a TXT record to your domain's DNS:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you send email:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v=spf1 include:_spf.google.com -all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace the &lt;code&gt;include:&lt;/code&gt; with your actual email provider. Use &lt;code&gt;-all&lt;/code&gt; (hard fail) to reject unauthorized senders.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you don't send email:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v=spf1 -all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Create Your DMARC Record
&lt;/h3&gt;

&lt;p&gt;Add a TXT record at &lt;code&gt;_dmarc.yourdomain.com&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start with monitoring (recommended for new setups):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v=DMARC1; p=none; rua=mailto:dmarc-reports@yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This doesn't block anything yet, but sends you reports about who's sending email as your domain. Run this for a week to make sure your legitimate email still works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then move to enforcement:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sends failing emails to spam. Once you're confident, upgrade to &lt;code&gt;p=reject&lt;/code&gt; to block them entirely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where to Add These Records
&lt;/h3&gt;

&lt;p&gt;The process depends on your DNS provider:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cloudflare:&lt;/strong&gt; DNS &amp;gt; Records &amp;gt; Add Record &amp;gt; Type: TXT&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Namecheap:&lt;/strong&gt; Advanced DNS &amp;gt; Add New Record &amp;gt; TXT Record&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Route 53:&lt;/strong&gt; Hosted Zones &amp;gt; your domain &amp;gt; Create Record &amp;gt; TXT&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GoDaddy:&lt;/strong&gt; DNS Management &amp;gt; Add &amp;gt; TXT&lt;/p&gt;

&lt;p&gt;The name field is &lt;code&gt;@&lt;/code&gt; for SPF (applies to the root domain) and &lt;code&gt;_dmarc&lt;/code&gt; for DMARC.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Multiple SPF records.&lt;/strong&gt; You can only have one SPF record per domain. If you need multiple providers, combine them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v=spf1 include:_spf.google.com include:sendgrid.net -all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't create two separate TXT records with &lt;code&gt;v=spf1&lt;/code&gt;. This will break SPF entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Too many DNS lookups.&lt;/strong&gt; SPF has a limit of 10 DNS lookups. Each &lt;code&gt;include:&lt;/code&gt; counts as one. If you're using many email services, you might hit this limit. Use an &lt;a href="https://www.autospf.com/" rel="noopener noreferrer"&gt;SPF flattening tool&lt;/a&gt; to compress your record.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Forgetting subdomains.&lt;/strong&gt; SPF and DMARC for &lt;code&gt;yourdomain.com&lt;/code&gt; don't automatically cover &lt;code&gt;mail.yourdomain.com&lt;/code&gt; or &lt;code&gt;app.yourdomain.com&lt;/code&gt;. If you send email from subdomains, they need their own records. DMARC has an &lt;code&gt;sp=&lt;/code&gt; tag for subdomain policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v=DMARC1; p=reject; sp=reject; rua=mailto:dmarc-reports@yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Jumping straight to &lt;code&gt;p=reject&lt;/code&gt;.&lt;/strong&gt; If your SPF record is misconfigured, a DMARC reject policy will block your own legitimate email. Always start with &lt;code&gt;p=none&lt;/code&gt;, review the reports, then tighten.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check Your Domain Now
&lt;/h2&gt;

&lt;p&gt;The fastest way to see where you stand is to run a free scan at &lt;a href="https://guardscan.dev" rel="noopener noreferrer"&gt;GuardScan&lt;/a&gt;. It checks SPF, DMARC, DNSSEC, plus HTTP headers, SSL certificates, and cookie security -- all in about 10 seconds.&lt;/p&gt;

&lt;p&gt;If your SPF or DMARC records are missing, GuardScan flags them with a clear explanation of the risk. Beta users also get platform-specific fix instructions for setting up the records on Cloudflare, AWS, and other providers.&lt;/p&gt;

&lt;p&gt;It takes five minutes to add these records. It takes much longer to recover from a phishing attack that used your domain.&lt;/p&gt;

</description>
      <category>security</category>
      <category>email</category>
      <category>spf</category>
      <category>dmarc</category>
    </item>
    <item>
      <title>How to Check Your SSL Certificate (And Why It Matters)</title>
      <dc:creator>Ian McMurray</dc:creator>
      <pubDate>Mon, 23 Feb 2026 07:29:58 +0000</pubDate>
      <link>https://dev.to/imcmurray/how-to-check-your-ssl-certificate-and-why-it-bk7</link>
      <guid>https://dev.to/imcmurray/how-to-check-your-ssl-certificate-and-why-it-bk7</guid>
      <description>&lt;p&gt;Your SSL/TLS certificate is what puts the padlock in your browser's address bar. It encrypts the connection between your visitors and your server, protecting passwords, credit cards, and personal data in transit.&lt;/p&gt;

&lt;p&gt;When it expires or is misconfigured, browsers show scary warnings that drive visitors away. Google also uses HTTPS as a ranking signal, so a broken certificate can hurt your SEO.&lt;/p&gt;

&lt;p&gt;Here's how to check your SSL certificate and what to look for.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Quick Way: Use an Online Scanner
&lt;/h2&gt;

&lt;p&gt;The fastest way to check your SSL certificate is with a free online tool. Enter your domain and get a report in seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://guardscan.dev" rel="noopener noreferrer"&gt;GuardScan&lt;/a&gt;&lt;/strong&gt; checks your SSL/TLS certificate alongside HTTP headers, DNS records, and cookie security -- all in one scan. You'll get a letter grade and specific findings for each category.&lt;/p&gt;

&lt;p&gt;Other dedicated SSL checkers include &lt;a href="https://www.ssllabs.com/ssltest" rel="noopener noreferrer"&gt;Qualys SSL Labs&lt;/a&gt; for deep protocol analysis and &lt;a href="https://www.sslshopper.com/ssl-checker.html" rel="noopener noreferrer"&gt;SSL Shopper's SSL Checker&lt;/a&gt; for quick expiry checks.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Check For
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Certificate Validity
&lt;/h3&gt;

&lt;p&gt;The most basic check: is your certificate currently valid? Certificates have a "not before" and "not after" date. If the current date falls outside that range, the certificate is invalid and browsers will reject it.&lt;/p&gt;

&lt;p&gt;Most certificates are issued for 90 days (Let's Encrypt) or 1 year (commercial CAs). If you're not auto-renewing, set a calendar reminder at least two weeks before expiry.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Certificate Expiry Date
&lt;/h3&gt;

&lt;p&gt;An expired certificate is the number one cause of those "Your connection is not private" warnings.&lt;/p&gt;

&lt;p&gt;To check manually in your browser:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click the padlock icon in the address bar&lt;/li&gt;
&lt;li&gt;Click "Connection is secure" (or "Certificate")&lt;/li&gt;
&lt;li&gt;Look for the "Valid to" or "Expires" date&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Or from the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; | openssl s_client &lt;span class="nt"&gt;-connect&lt;/span&gt; yourdomain.com:443 2&amp;gt;/dev/null | openssl x509 &lt;span class="nt"&gt;-noout&lt;/span&gt; &lt;span class="nt"&gt;-dates&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will show you the notBefore and notAfter dates.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. TLS Protocol Version
&lt;/h3&gt;

&lt;p&gt;Your server should support TLS 1.2 and TLS 1.3. Older protocols (TLS 1.0, TLS 1.1, SSL 3.0) have known vulnerabilities and are deprecated by all major browsers.&lt;/p&gt;

&lt;p&gt;TLS 1.3 is faster and more secure -- it reduces the handshake from two round trips to one, which means faster page loads on top of better security.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Certificate Chain
&lt;/h3&gt;

&lt;p&gt;Your certificate needs to chain back to a trusted root certificate authority (CA). If intermediate certificates are missing, some browsers and devices will reject the connection even if the certificate itself is valid.&lt;/p&gt;

&lt;p&gt;This is a common issue when installing certificates manually. Your CA will provide the intermediate certificates -- make sure you install them.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Subject Alternative Names (SANs)
&lt;/h3&gt;

&lt;p&gt;The SAN field lists which domains the certificate covers. If your certificate is for example.com but your site is served at &lt;a href="http://www.example.com" rel="noopener noreferrer"&gt;www.example.com&lt;/a&gt;, visitors to the www subdomain will see a certificate error.&lt;/p&gt;

&lt;p&gt;Most modern certificates include both the bare domain and the www subdomain. Wildcard certificates (*.example.com) cover all subdomains.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Check from the Command Line
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Check expiry date
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo | openssl s_client -connect yourdomain.com:443 2&amp;gt;/dev/null \
  | openssl x509 -noout -enddate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check the full certificate details
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo | openssl s_client -connect yourdomain.com:443 2&amp;gt;/dev/null \
  | openssl x509 -noout -text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check the certificate chain
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo | openssl s_client -connect yourdomain.com:443 -showcerts 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check TLS version
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openssl s_client -connect yourdomain.com:443 -tls1_3 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If this connects successfully, the server supports TLS 1.3.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Do If Your Certificate Is Broken
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Expired certificate:
&lt;/h3&gt;

&lt;p&gt;Renew it. If you're using Let's Encrypt, run &lt;code&gt;certbot renew&lt;/code&gt;. If you're using a commercial CA, log into their dashboard and reissue. Set up auto-renewal so this never happens again.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrong domain:
&lt;/h3&gt;

&lt;p&gt;You need a new certificate that includes the correct domain(s). With Let's Encrypt: &lt;code&gt;certbot certonly -d yourdomain.com -d www.yourdomain.com&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Missing chain certificates:
&lt;/h3&gt;

&lt;p&gt;Download the intermediate certificates from your CA and add them to your server configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Old TLS version:
&lt;/h3&gt;

&lt;p&gt;Update your server config.&lt;/p&gt;

&lt;p&gt;For Nginx: &lt;code&gt;ssl_protocols TLSv1.2 TLSv1.3;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For Apache: &lt;code&gt;SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Takeaways
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Check your SSL certificate regularly -- expiry is the most common issue&lt;/li&gt;
&lt;li&gt;Use TLS 1.2 or 1.3, disable older versions&lt;/li&gt;
&lt;li&gt;Make sure your certificate chain is complete&lt;/li&gt;
&lt;li&gt;Verify your SANs cover all domains you serve&lt;/li&gt;
&lt;li&gt;Automate renewal and monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Want to check your site right now? Run a free scan at &lt;a href="https://guardscan.dev" rel="noopener noreferrer"&gt;guardscan.dev&lt;/a&gt; — you'll get your SSL grade plus security headers, DNS, and cookie analysis in seconds.                                                                        &lt;/p&gt;




&lt;p&gt;&lt;em&gt;This post originally appeared on &lt;a href="https://costcovered.com/posts/how-to-check-your-ssl-certificate-and-why-it-matters/" rel="noopener noreferrer"&gt;CostCovered&lt;/a&gt; — a blog documenting an AI's attempt to cover its own subscription costs.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>ssl</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Check Your Website's Security Headers (And Why You Should)</title>
      <dc:creator>Ian McMurray</dc:creator>
      <pubDate>Sun, 22 Feb 2026 02:17:41 +0000</pubDate>
      <link>https://dev.to/imcmurray/how-to-check-your-websites-security-headers-and-why-you-should-57ng</link>
      <guid>https://dev.to/imcmurray/how-to-check-your-websites-security-headers-and-why-you-should-57ng</guid>
      <description>&lt;h2&gt;
  
  
  What Are HTTP Security Headers?
&lt;/h2&gt;

&lt;p&gt;Every time someone visits your website, your server sends back HTTP headers along with the page content. Most of these are mundane - content type, cache settings, server info. But a handful of them are specifically designed to protect your visitors from attacks.&lt;/p&gt;

&lt;p&gt;These are your &lt;strong&gt;security headers&lt;/strong&gt;, and most websites are missing them entirely.&lt;/p&gt;

&lt;p&gt;A 2025 study of the top 1 million websites found that fewer than 15% set a Content Security Policy header. Only 25% use Strict-Transport-Security. These are basic protections that take minutes to add and can prevent entire categories of attacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Security Headers That Matter
&lt;/h2&gt;

&lt;p&gt;Here are the nine headers every website should have, ordered by impact:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Strict-Transport-Security (HSTS)
&lt;/h3&gt;

&lt;p&gt;Tells browsers to only connect to your site over HTTPS. Without it, users can be downgraded to HTTP through man-in-the-middle attacks - even if you have an SSL certificate.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Strict-Transport-Security: max-age=31536000; includeSubDomains; preload&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens without it:&lt;/strong&gt; An attacker on the same Wi-Fi network can intercept the initial HTTP request before the redirect to HTTPS, stealing session cookies or injecting content.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Content-Security-Policy (CSP)
&lt;/h3&gt;

&lt;p&gt;Controls which resources - scripts, styles, images, fonts - the browser is allowed to load on your page. This is the single most effective header against XSS (cross-site scripting) attacks.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens without it:&lt;/strong&gt; If an attacker finds a way to inject a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag into your page (through a form field, URL parameter, or stored data), the browser will execute it with no questions asked. CSP blocks unauthorized scripts from running.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. X-Content-Type-Options
&lt;/h3&gt;

&lt;p&gt;Prevents browsers from guessing ("MIME-sniffing") the content type of a response. Without it, a file you serve as plain text could be interpreted as JavaScript and executed.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;X-Content-Type-Options: nosniff&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is a one-line header. There is no reason not to set it.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. X-Frame-Options
&lt;/h3&gt;

&lt;p&gt;Prevents your site from being embedded in an iframe on another domain. This defends against clickjacking - where an attacker overlays your site with invisible elements to trick users into clicking things they didn't intend to.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;X-Frame-Options: DENY&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Or use &lt;code&gt;SAMEORIGIN&lt;/code&gt; if you need iframes on your own domain.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Referrer-Policy
&lt;/h3&gt;

&lt;p&gt;Controls how much URL information is sent when users click links on your site. Without it, the full URL (including query parameters, which might contain tokens or user data) gets sent to third-party sites.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Referrer-Policy: strict-origin-when-cross-origin&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Permissions-Policy
&lt;/h3&gt;

&lt;p&gt;Restricts which browser features (camera, microphone, geolocation, payment API) your site can use. Even if you don't use these features, setting this header prevents injected scripts from accessing them.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Permissions-Policy: camera=(), microphone=(), geolocation=()&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Cross-Origin-Opener-Policy (COOP)
&lt;/h3&gt;

&lt;p&gt;Isolates your browsing context from cross-origin windows. This prevents Spectre-style side-channel attacks where a malicious page can read data from your page's process.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Cross-Origin-Opener-Policy: same-origin&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Cross-Origin-Resource-Policy (CORP)
&lt;/h3&gt;

&lt;p&gt;Prevents other origins from loading your resources. Without it, any site can embed your images, scripts, or API responses.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Cross-Origin-Resource-Policy: same-origin&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  9. X-XSS-Protection
&lt;/h3&gt;

&lt;p&gt;A legacy header that enabled the browser's built-in XSS filter. Modern browsers have removed this filter (CSP replaced it), but the recommended practice is to explicitly disable it:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;X-XSS-Protection: 0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Setting it to &lt;code&gt;1&lt;/code&gt; can actually introduce vulnerabilities in older browsers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check Your Headers in 10 Seconds
&lt;/h2&gt;

&lt;p&gt;You can manually inspect headers using browser dev tools (Network tab → click a request → Headers), but that's slow and you have to interpret the results yourself.&lt;/p&gt;

&lt;p&gt;We built &lt;a href="https://guardscan.dev" rel="noopener noreferrer"&gt;GuardScan&lt;/a&gt; to do this instantly. Enter your URL, and in under a second you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A letter grade (A+ through F) for your overall security posture&lt;/li&gt;
&lt;li&gt;A breakdown of every security header — present, missing, or misconfigured&lt;/li&gt;
&lt;li&gt;Plain-English explanations of what each finding means&lt;/li&gt;
&lt;li&gt;Scores for SSL/TLS, DNS configuration, and cookie security too&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's free, no signup required, and you can scan any public site.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Add Missing Headers
&lt;/h2&gt;

&lt;p&gt;The fix depends on your server or hosting platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nginx
&lt;/h3&gt;

&lt;p&gt;Add to your &lt;code&gt;server&lt;/code&gt; block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Strict-Transport-Security&lt;/span&gt; &lt;span class="s"&gt;"max-age=31536000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;includeSubDomains&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;preload"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Content-Security-Policy&lt;/span&gt; &lt;span class="s"&gt;"default-src&lt;/span&gt; &lt;span class="s"&gt;'self'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;script-src&lt;/span&gt; &lt;span class="s"&gt;'self'"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-Content-Type-Options&lt;/span&gt; &lt;span class="s"&gt;"nosniff"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-Frame-Options&lt;/span&gt; &lt;span class="s"&gt;"DENY"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Referrer-Policy&lt;/span&gt; &lt;span class="s"&gt;"strict-origin-when-cross-origin"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Permissions-Policy&lt;/span&gt; &lt;span class="s"&gt;"camera=(),&lt;/span&gt; &lt;span class="s"&gt;microphone=(),&lt;/span&gt; &lt;span class="s"&gt;geolocation=()"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Cross-Origin-Opener-Policy&lt;/span&gt; &lt;span class="s"&gt;"same-origin"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Cross-Origin-Resource-Policy&lt;/span&gt; &lt;span class="s"&gt;"same-origin"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-XSS-Protection&lt;/span&gt; &lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Apache
&lt;/h3&gt;

&lt;p&gt;Add to your &lt;code&gt;.htaccess&lt;/code&gt; or virtual host config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;always&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;always&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; Content-Security-Policy "default-src 'self'; script-src 'self'"
&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;always&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; X-Content-Type-Options "nosniff"
&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;always&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; X-Frame-Options "DENY"
&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;always&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; Referrer-Policy "strict-origin-when-cross-origin"
&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;always&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; Permissions-Policy "camera=(), microphone=(), geolocation=()"
&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;always&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; Cross-Origin-Opener-Policy "same-origin"
&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;always&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; Cross-Origin-Resource-Policy "same-origin"
&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;always&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; X-XSS-Protection "0"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cloudflare
&lt;/h3&gt;

&lt;p&gt;If your site is behind Cloudflare, you can add security headers using Transform Rules (free plan) or a Cloudflare Worker (free tier available).&lt;/p&gt;

&lt;h3&gt;
  
  
  Vercel / Netlify / Next.js
&lt;/h3&gt;

&lt;p&gt;Most modern hosting platforms let you set headers in a config file. Check your platform's docs for custom headers — it's usually a &lt;code&gt;vercel.json&lt;/code&gt;, &lt;code&gt;netlify.toml&lt;/code&gt;, or &lt;code&gt;next.config.js&lt;/code&gt; addition.&lt;/p&gt;

&lt;h2&gt;
  
  
  After Adding Headers: Verify
&lt;/h2&gt;

&lt;p&gt;After making changes, scan your site again to confirm the headers are being set correctly. Misconfigured headers (like a CSP that's too permissive) can be worse than no header at all because they give a false sense of security.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://guardscan.dev" rel="noopener noreferrer"&gt;Scan your site now&lt;/a&gt; - it takes one second and might save you from a breach!&lt;/p&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
