Detect SPF all mechanism
This commit is contained in:
parent
a6448a1533
commit
326abc0744
3 changed files with 65 additions and 27 deletions
|
|
@ -867,6 +867,11 @@ components:
|
|||
type: boolean
|
||||
description: Whether the SPF record is valid
|
||||
example: true
|
||||
all_qualifier:
|
||||
type: string
|
||||
enum: ["+", "-", "~", "?"]
|
||||
description: "Qualifier for the 'all' mechanism: + (pass), - (fail), ~ (softfail), ? (neutral)"
|
||||
example: "~"
|
||||
error:
|
||||
type: string
|
||||
description: Error message if validation failed
|
||||
|
|
|
|||
|
|
@ -245,28 +245,34 @@ func (d *DNSAnalyzer) resolveSPFRecords(domain string, visited map[string]bool,
|
|||
// Basic validation
|
||||
valid := d.validateSPF(spfRecord)
|
||||
|
||||
// Check for strict -all mechanism
|
||||
// Extract the "all" mechanism qualifier
|
||||
var allQualifier *api.SPFRecordAllQualifier
|
||||
var errMsg *string
|
||||
|
||||
if !valid {
|
||||
errMsg = api.PtrTo("SPF record appears malformed")
|
||||
} else if !d.hasSPFStrictFail(spfRecord) {
|
||||
// Check what mechanism is used
|
||||
if strings.HasSuffix(spfRecord, " ~all") {
|
||||
errMsg = api.PtrTo("SPF uses ~all (softfail) instead of -all (hardfail). This weakens email authentication and may reduce deliverability.")
|
||||
} else if strings.HasSuffix(spfRecord, " +all") || strings.HasSuffix(spfRecord, " ?all") {
|
||||
errMsg = api.PtrTo("SPF uses permissive 'all' mechanism. This severely weakens email authentication. Use -all for strict policy.")
|
||||
} else {
|
||||
// Extract qualifier from the "all" mechanism
|
||||
if strings.HasSuffix(spfRecord, " -all") {
|
||||
allQualifier = api.PtrTo(api.SPFRecordAllQualifier("-"))
|
||||
} else if strings.HasSuffix(spfRecord, " ~all") {
|
||||
allQualifier = api.PtrTo(api.SPFRecordAllQualifier("~"))
|
||||
} else if strings.HasSuffix(spfRecord, " +all") {
|
||||
allQualifier = api.PtrTo(api.SPFRecordAllQualifier("+"))
|
||||
} else if strings.HasSuffix(spfRecord, " ?all") {
|
||||
allQualifier = api.PtrTo(api.SPFRecordAllQualifier("?"))
|
||||
} else if strings.HasSuffix(spfRecord, " all") {
|
||||
errMsg = api.PtrTo("SPF uses neutral 'all' mechanism. Use -all for strict policy to improve deliverability.")
|
||||
} else {
|
||||
errMsg = api.PtrTo("SPF record should end with -all for strict policy to improve deliverability and prevent spoofing.")
|
||||
// Implicit + qualifier (default)
|
||||
allQualifier = api.PtrTo(api.SPFRecordAllQualifier("+"))
|
||||
}
|
||||
}
|
||||
|
||||
results = append(results, api.SPFRecord{
|
||||
Domain: &domain,
|
||||
Record: &spfRecord,
|
||||
Valid: valid,
|
||||
Error: errMsg,
|
||||
Domain: &domain,
|
||||
Record: &spfRecord,
|
||||
Valid: valid,
|
||||
AllQualifier: allQualifier,
|
||||
Error: errMsg,
|
||||
})
|
||||
|
||||
// Extract and resolve include: directives
|
||||
|
|
@ -694,23 +700,23 @@ func (d *DNSAnalyzer) CalculateDNSScore(results *api.DNSResults) (int, string) {
|
|||
mainSPF := (*results.SpfRecords)[0]
|
||||
if mainSPF.Valid {
|
||||
// Full points for valid SPF
|
||||
score += 20
|
||||
score += 15
|
||||
|
||||
// Check for strict -all mechanism
|
||||
if mainSPF.Record != nil && !d.hasSPFStrictFail(*mainSPF.Record) {
|
||||
// Deduct points for weak SPF policy
|
||||
if strings.HasSuffix(*mainSPF.Record, " ~all") {
|
||||
// Deduct points based on the all mechanism qualifier
|
||||
if mainSPF.AllQualifier != nil {
|
||||
switch *mainSPF.AllQualifier {
|
||||
case "-":
|
||||
// Strict fail - no deduction, this is the recommended policy
|
||||
score += 5
|
||||
case "~":
|
||||
// Softfail - moderate penalty
|
||||
score -= 5
|
||||
} else if strings.HasSuffix(*mainSPF.Record, " +all") ||
|
||||
strings.HasSuffix(*mainSPF.Record, " ?all") ||
|
||||
strings.HasSuffix(*mainSPF.Record, " all") {
|
||||
case "+", "?":
|
||||
// Pass/neutral - severe penalty
|
||||
score -= 10
|
||||
} else {
|
||||
// No 'all' mechanism at all - severe penalty
|
||||
score -= 10
|
||||
score -= 5
|
||||
}
|
||||
} else {
|
||||
// No 'all' mechanism qualifier extracted - severe penalty
|
||||
score -= 5
|
||||
}
|
||||
} else if mainSPF.Record != nil {
|
||||
// Partial credit if SPF record exists but has issues
|
||||
|
|
|
|||
|
|
@ -50,6 +50,33 @@
|
|||
<span class="badge bg-danger">Invalid</span>
|
||||
{/if}
|
||||
</div>
|
||||
{#if spf.all_qualifier}
|
||||
<div class="mb-2">
|
||||
<strong>All Mechanism Policy:</strong>
|
||||
{#if spf.all_qualifier === '-'}
|
||||
<span class="badge bg-success">Strict (-all)</span>
|
||||
{:else if spf.all_qualifier === '~'}
|
||||
<span class="badge bg-warning">Softfail (~all)</span>
|
||||
{:else if spf.all_qualifier === '+'}
|
||||
<span class="badge bg-danger">Pass (+all)</span>
|
||||
{:else if spf.all_qualifier === '?'}
|
||||
<span class="badge bg-warning">Neutral (?all)</span>
|
||||
{/if}
|
||||
{#if index === 0}
|
||||
<div class="alert small mt-2" class:alert-warning={spf.all_qualifier !== '-'} class:alert-success={spf.all_qualifier === '-'}>
|
||||
{#if spf.all_qualifier === '-'}
|
||||
All unauthorized servers will be rejected. This is the recommended strict policy.
|
||||
{:else if spf.all_qualifier === '~'}
|
||||
Unauthorized servers will softfail. Consider using <code>-all</code> for stricter policy, though this rarely affects legitimate email deliverability.
|
||||
{:else if spf.all_qualifier === '+'}
|
||||
All servers are allowed to send email. This severely weakens email authentication. Use <code>-all</code> for strict policy.
|
||||
{:else if spf.all_qualifier === '?'}
|
||||
No statement about unauthorized servers. Use <code>-all</code> for strict policy to prevent spoofing.
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{#if spf.record}
|
||||
<div class="mb-2">
|
||||
<strong>Record:</strong><br>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue