Test SMB Signing Before You Require It
Last edited on August 11, 2026

SMB signing can be supported on both endpoints and still not be required. That distinction matters because a policy screen that says “enabled” is not an enforcement receipt. For SMB 2.02 and later, a session is signed when either endpoint requires signing; it can remain unsigned only when neither endpoint requires it.

This guide turns that rule into a test you can run before a domain-wide change. A loopback-only Samba lab advertises “enabled but not required,” then “enabled and required.” It transfers the same file through each accepted path, proves a current capable client signs when the server demands it even when the client’s preference is off, and deliberately corrupts signed requests to verify that the server rejects them.

The reproduction uses a disposable Debian 13 host with Samba 4.22.10, smbclient, Nmap and Python 3. Run it as root on an isolated test host, never on a production file server. The Windows inventory and GPO plan that follow are production guidance; the blocks marked as tested evidence are the exact Linux/Samba acceptance model reproduced for this article.

Required Is the Enforcement Decision

Microsoft’s current SMB signing overview says the signature covers the message, sender and recipient using a session-derived key. A changed message no longer matches its signature. This provides integrity and helps resist relay and spoofing paths; it does not encrypt file contents.

For SMB2 and SMB3, do not build a rollout around EnableSecuritySignature. Microsoft’s 2026 troubleshooting matrix states that this value is ignored for SMB 2.02 and later. RequireSecuritySignature is the effective decision.

Client requires Server requires Expected session Operator decision
No No Signing is not guaranteed Not an enforcement state
Yes No Signed Client protects outbound SMB
No Yes Signed if the client is capable Server protects inbound SMB
Yes Yes Signed Strongest declared requirement
For SMB2+, either endpoint can require signing; “enabled” alone is not the same as “required.”

Current defaults are also version-specific. Microsoft’s control guide says Windows 11 24H2 Enterprise, Pro and Education require inbound and outbound signing, Windows Server 2025 requires outbound signing, and Windows 11 24H2 Home does not require either direction. Inventory the effective client and server roles instead of assuming an operating-system label tells the whole story.

Inventory Windows Before You Enforce Anything

Every Windows machine can be an SMB client, an SMB server, or both. Capture both configurations and existing connections in an elevated PowerShell session. These commands are an inventory template, not evidence from the Linux lab:

$receipt = [ordered]@{
  Computer = $env:COMPUTERNAME
  Client = Get-SmbClientConfiguration |
    Select-Object EnableSecuritySignature,RequireSecuritySignature,
      AuditServerDoesNotSupportSigning
  Server = Get-SmbServerConfiguration |
    Select-Object EnableSecuritySignature,RequireSecuritySignature,
      AuditClientDoesNotSupportSigning
  Connections = Get-SmbConnection |
    Select-Object ServerName,ShareName,Dialect,Signed,Encrypted,UserName
}
$receipt | ConvertTo-Json -Depth 4
Get-SmbSession | Select-Object ClientComputerName,ClientUserName,Dialect,Encrypted

Record business identity beside protocol identity: server name, share, owning application, device type, authentication method and a named owner. Connecting by IP address or an arbitrary CNAME can move authentication away from Kerberos, so test the same UNC name users and services actually use. A failed name, authentication, firewall or transport path is not automatically a signing failure. If the fault appears only after Windows maintenance, preserve the same kind of tested return path used in a Windows Server patching change.

Windows 11 24H2 adds auditing for peers that do not support signing. Enable the relevant client and server audit settings during discovery, then review Microsoft-Windows-SMBClient/Audit events 31998 and 31999 and Microsoft-Windows-SMBServer/Audit events 3021 and 3022. An event is a lead: map it back to the exact share, device and owner before setting a deadline.

Create a Collision-Safe Loopback Lab

The lab binds only 127.0.0.1:1445, creates one synthetic system account and refuses to reuse its path, account or port. Keep all blocks in the same root shell so the variables and cleanup trap survive.

set -Eeuo pipefail
LAB=/tmp/voxfor-smb-signing-lab
LAB_USER=voxfor_smb_lab
LAB_PASSWORD='Synthetic-SMB-Lab-Only!'
PORT=1445

test ! -e "$LAB"
! id "$LAB_USER" >/dev/null 2>&1
! ss -ltn "sport = :$PORT" | tail -n +2 | grep -q .

install -d -m 0755 "$LAB"
touch "$LAB/.voxfor-smb-signing-lab"
install -d -m 0700 "$LAB"/{private,lock,state,cache,run,log,ncalrpc,client}
install -d -m 0750 "$LAB/share"
useradd --system --no-create-home --shell /usr/sbin/nologin "$LAB_USER"
chown "$LAB_USER:$LAB_USER" "$LAB/share"
printf '%s\n' 'signed transport receipt' >"$LAB/share/marker.txt"
chown "$LAB_USER:$LAB_USER" "$LAB/share/marker.txt"

SMBD_PID=
cleanup_smb_lab() {
  if [[ -n "${SMBD_PID:-}" ]] && kill -0 "$SMBD_PID" 2>/dev/null; then
    kill "$SMBD_PID"; wait "$SMBD_PID" 2>/dev/null || true
  fi
  id "$LAB_USER" >/dev/null 2>&1 && userdel "$LAB_USER"
  if [[ -f "$LAB/.voxfor-smb-signing-lab" ]]; then
    rm -rf --one-file-system "$LAB"
  fi
}
trap cleanup_smb_lab EXIT

Install samba, smbclient and nmap from your disposable host’s signed package repositories first. The official Samba smb.conf reference calls the optional state auto and the required state mandatory. Samba’s normalized testparm output renders them as if_required and required.

Prove “Enabled but Not Required”

The first server supports signing without mandating it. The custom Nmap port argument matters because the fixture deliberately avoids TCP 445; the leading + forces the host script outside its standard port rule.

cat >"$LAB/smb-auto.conf" <<'CONF'
[global]
  workgroup = VOXFORLAB
  server role = standalone server
  security = user
  interfaces = 127.0.0.1
  bind interfaces only = yes
  smb ports = 1445
  server min protocol = SMB2_02
  server max protocol = SMB3
  server signing = auto
  map to guest = Never
  load printers = no
  disable spoolss = yes
  log file = /tmp/voxfor-smb-signing-lab/log/log.%m
  pid directory = /tmp/voxfor-smb-signing-lab/run
  lock directory = /tmp/voxfor-smb-signing-lab/lock
  state directory = /tmp/voxfor-smb-signing-lab/state
  cache directory = /tmp/voxfor-smb-signing-lab/cache
  private dir = /tmp/voxfor-smb-signing-lab/private
  ncalrpc dir = /tmp/voxfor-smb-signing-lab/ncalrpc
  passdb backend = tdbsam:/tmp/voxfor-smb-signing-lab/private/passdb.tdb
[receipt]
  path = /tmp/voxfor-smb-signing-lab/share
  read only = no
  guest ok = no
  valid users = voxfor_smb_lab
CONF

printf '%s\n%s\n' "$LAB_PASSWORD" "$LAB_PASSWORD" |
  smbpasswd -s -a "$LAB_USER" -c "$LAB/smb-auto.conf" >/dev/null
smbd -D -s "$LAB/smb-auto.conf" -p "$PORT"
SMBD_PID=$(cat "$LAB/run/smbd.pid")
testparm -s "$LAB/smb-auto.conf" 2>/dev/null | grep 'server signing'
nmap -Pn -p "$PORT" --script '+smb2-security-mode' \
  --script-args "smbport=$PORT" 127.0.0.1

The accepted probe is Message signing enabled but not required. That describes the server’s advertised requirement; it does not prove that a particular live client chose an unsigned session. Test both client preferences and preserve the file bytes.

for signing in off required; do
  smbclient //127.0.0.1/receipt -p "$PORT" \
    -U "$LAB_USER%$LAB_PASSWORD" -m SMB3 \
    --option="client signing=$signing" \
    -c "get marker.txt $LAB/client/optional-$signing.txt"
  sha256sum "$LAB/client/optional-$signing.txt"
done
sha256sum "$LAB/share/marker.txt"
cmp "$LAB/share/marker.txt" "$LAB/client/optional-off.txt"
cmp "$LAB/share/marker.txt" "$LAB/client/optional-required.txt"

Both transfers succeeded in the reproduced lab and matched the source hash. The important conclusion is narrow: the optional server accepts a modern client that requires signing, but the server policy itself does not force every client to do so.

Switch Only the Server Requirement

Stop the optional server, copy its complete configuration and change one line. This isolates the policy variable instead of changing identity, credentials, protocol floor and share at the same time.

kill "$SMBD_PID"; wait "$SMBD_PID" 2>/dev/null || true; SMBD_PID=
cp "$LAB/smb-auto.conf" "$LAB/smb-required.conf"
sed -i 's/server signing = auto/server signing = mandatory/' \
  "$LAB/smb-required.conf"
smbd -D -s "$LAB/smb-required.conf" -p "$PORT"
SMBD_PID=$(cat "$LAB/run/smbd.pid")
testparm -s "$LAB/smb-required.conf" 2>/dev/null | grep 'server signing'
nmap -Pn -p "$PORT" --script '+smb2-security-mode' \
  --script-args "smbport=$PORT" 127.0.0.1

The expected result is server signing = required and Message signing enabled and required. The Nmap security-mode script reads the SMB2 negotiation response independently of the Samba config file, so the receipt contains both declared and advertised states.

A current capable client may still connect even when its local preference says off: the server’s requirement wins and the client signs. Treat this as a compatibility success, not proof that the required policy was bypassed.

smbclient //127.0.0.1/receipt -p "$PORT" \
  -U "$LAB_USER%$LAB_PASSWORD" -m SMB3 \
  --option='client signing=off' \
  -c "get marker.txt $LAB/client/required-server-client-off.txt"
cmp "$LAB/share/marker.txt" "$LAB/client/required-server-client-off.txt"
sha256sum "$LAB/client/required-server-client-off.txt"

Use a Real Integrity Negative Control

Changing a capable client’s preference is not a reliable incompatible-client simulator. The reproduced negative control instead proxies one loopback connection and flips the first byte of every signed SMB2 request signature after authentication. The message remains structurally valid, but its signature is wrong.

cat >"$LAB/tamper_proxy.py" <<'PY'
import select, socket, struct
listen=socket.socket(); listen.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
listen.bind(('127.0.0.1',1446)); listen.listen(1)
client,_=listen.accept(); server=socket.create_connection(('127.0.0.1',1445))
client.setblocking(False); server.setblocking(False)
peers={client:server,server:client}; buffers={client:bytearray(),server:bytearray()}
tampered=0
while peers:
    ready,_,_=select.select(list(peers),[],[],10)
    if not ready: break
    for source in ready:
        chunk=source.recv(65536)
        if not chunk:
            for sock in list(peers): sock.close()
            peers.clear(); break
        buffers[source].extend(chunk)
        buf=buffers[source]
        while len(buf)>=4:
            length=int.from_bytes(buf[:4],'big') & 0x00ffffff
            if len(buf)<4+length: break
            frame=bytearray(buf[:4+length]); del buf[:4+length]
            if source is client and len(frame)>=68 and frame[4:8]==b'\xfeSMB':
                flags=struct.unpack_from('<I',frame,20)[0]
                if flags & 0x00000008:
                    frame[52] ^= 1; tampered += 1
            peers[source].sendall(frame)
print(f'tampered_signed_requests={tampered}')
raise SystemExit(0 if tampered else 2)
PY

python3 -u "$LAB/tamper_proxy.py" >"$LAB/client/tamper.log" &
PROXY_PID=$!
sleep 0.2
set +e
smbclient //127.0.0.1/receipt -p 1446 \
  -U "$LAB_USER%$LAB_PASSWORD" -m SMB3 \
  --option='client signing=required' -c 'ls' \
  >"$LAB/client/tampered-client.log" 2>&1
TAMPER_RC=$?
wait "$PROXY_PID"; PROXY_RC=$?
set -e
test "$TAMPER_RC" -ne 0
test "$PROXY_RC" -eq 0
grep 'tampered_signed_requests=' "$LAB/client/tamper.log"
grep -E 'NT_STATUS_(ACCESS_DENIED|INVALID_SIGNATURE)' \
  "$LAB/client/tampered-client.log"

The client exited 1 after tree connect failed: NT_STATUS_ACCESS_DENIED; the proxy reported three corrupted signed requests. That is evidence for message-integrity enforcement. It is not an attack tutorial: the proxy is loopback-only, uses a synthetic account and does not capture or forward production credentials.

Close the Positive Path and Cleanup

Finish with both endpoints requiring signing, compare every retrieved file with the source, and remove only the marked fixture. A transfer receipt should include content integrity, not just a successful ls.

smbclient //127.0.0.1/receipt -p "$PORT" \
  -U "$LAB_USER%$LAB_PASSWORD" -m SMB3 \
  --option='client signing=required' \
  -c "get marker.txt $LAB/client/required-both.txt"
for copy in \
  "$LAB/client/optional-off.txt" \
  "$LAB/client/optional-required.txt" \
  "$LAB/client/required-server-client-off.txt" \
  "$LAB/client/required-both.txt"; do
  cmp "$LAB/share/marker.txt" "$copy"
  sha256sum "$copy"
done
test -f "$LAB/.voxfor-smb-signing-lab"
cleanup_smb_lab
trap - EXIT
! id "$LAB_USER" >/dev/null 2>&1
test ! -e "$LAB"
! ss -ltn '( sport = :1445 or sport = :1446 )' |
  tail -n +2 | grep -q .
printf '%s\n' 'cleanup=passed'
environment=Debian 13 Samba/smbclient 4.22.10 Nmap 7.95 loopback=127.0.0.1:1445
optional_policy=server_signing_if_required
optional_probe=SMB3_11 Message signing enabled but not required
optional_off=success hash=147945a8166c7ea00ef639247bc12ad94ed968e1689a8d9a150ccce499d66efb
optional_required=success hash=147945a8166c7ea00ef639247bc12ad94ed968e1689a8d9a150ccce499d66efb
required_policy=server_signing_required
required_probe=SMB3_11 Message signing enabled and required
capable_client_preference_off=auto_signed_success hash=147945a8166c7ea00ef639247bc12ad94ed968e1689a8d9a150ccce499d66efb
tampered_signed_requests=3 client_exit=1 result=NT_STATUS_ACCESS_DENIED
required_both=success hash=147945a8166c7ea00ef639247bc12ad94ed968e1689a8d9a150ccce499d66efb
cleanup=passed temporary_user_absent ports_closed marked_lab_removed
SMB_SIGNING_LAB_OK

Accept the evidence model only when the optional config normalizes to if_required, Nmap reports “enabled but not required,” the required config normalizes to required, Nmap reports “enabled and required,” all four accepted transfers match the source SHA-256, the capable-client preference-off case still succeeds against the required server, signature corruption produces a nonzero client exit and an SMB access/signature failure, and cleanup leaves neither account, listener nor marked lab path.

Promote a Pilot, Not a Domain-Wide Surprise

Translate the lab into a production acceptance table. Include representative Windows clients, member servers, domain controllers, Samba hosts, NAS appliances, printers or scanners, backup agents, service accounts and scheduled jobs. Test named UNC paths and real read/write/rename behavior; a single workstation-to-file-server copy is not enough.

  1. Discover: enable the SMB client/server “does not support signing” audits and assign every event an owner.
  2. Baseline: export effective client/server configuration, live signed state, OS/firmware version and a small workload receipt.
  3. Pilot: link a dedicated GPO to one representative OU. Enable Microsoft network client: Digitally sign communications (always) for outbound enforcement and Microsoft network server: Digitally sign communications (always) for inbound enforcement as required by the scope.
  4. Accept: require policy application, named-path authentication, file operations, application jobs, acceptable transfer/CPU measurements and zero unexplained audit failures.
  5. Expand: move OU by OU only after the incompatibility ledger is empty or each exception has an owner, compensating control and expiry date.

Use the Signed property from Get-SmbConnection as session evidence, but keep workload behavior separate. If an application stops after enforcement, read the exact Windows and application logs before restarting repeatedly; the diagnostic discipline in the IIS 503 event and HTTPERR workflow applies even though the service differs. Protect the change with a recoverable system-state and application backup; if VSS is unhealthy, repair the failed Windows VSS writer before relying on that restore point.

Measure performance with the same clients, files, concurrency and network path before and after. A generic speed test cannot isolate SMB signing overhead; still, a repeatable route-and-direction network baseline helps prevent unrelated capacity changes from contaminating the comparison. Similarly, intermittent large-copy stalls can be an MTU symptom; investigate a path MTU black hole before blaming the signing policy.

Keep Rollback Narrow and Evidence-Rich

If the pilot fails, unlink or disable only the dedicated SMB-signing GPO from the affected pilot OU, run a controlled policy refresh or restart according to the change plan, remove existing test SMB connections, and require the pre-change named-UNC workload to pass. Do not disable signing domain-wide, re-enable guest access, or erase audit events as a shortcut. Preserve the failed peer, event ID, firmware/software version and workload result so the exception can be fixed rather than rediscovered.

A signing error can coexist with a different file-service problem. If the same dataset is also exported through NFS, a changed NFS export identity is a separate failure domain and should not be “fixed” by relaxing SMB policy. Promote only after protocol evidence and application evidence agree.

Frequently Asked Questions

What is the difference between SMB signing enabled and required?

Enabled means an endpoint supports signing and may negotiate it. Required means that endpoint refuses an SMB session that cannot meet the signing requirement. For SMB2 and SMB3, RequireSecuritySignature controls this decision; EnableSecuritySignature is ignored.

Does the client and server both need to require SMB signing?

No. A modern SMB2+ session is signed when either endpoint requires it and the peer is capable. Requiring both directions is useful when machines act as both clients and servers, but one endpoint’s requirement is sufficient for that connection.

How do I prove a live Windows SMB connection is signed?

Run Get-SmbConnection in elevated PowerShell and inspect ServerName, ShareName, Dialect, Signed and Encrypted. Reconnect after policy changes so you do not mistake a pre-existing session for a new negotiation.

Will requiring SMB signing break guest shares?

It can. Current Windows guidance warns that signing requirements and insecure guest access do not form a safe compatibility pair. Replace guest access with authenticated users and update or retire the third-party device instead of disabling signing as the first workaround.

Is SMB signing the same as SMB encryption?

No. Signing proves message integrity and authenticity; it does not hide the file contents. SMB encryption provides confidentiality and also protects integrity. Record both Signed and Encrypted when the data policy depends on them.

Why did a capable client connect when its signing preference was off?

Because the required server state controls the session. In the reproduced Samba lab, the modern client completed a signed SMB3 transfer even with its local preference set to off. That is expected compatibility behavior, not an enforcement bypass.

What should block a domain-wide SMB signing rollout?

Block promotion when any representative workload lacks a named owner, when a peer cannot sign, when named-path authentication changes unexpectedly, when file operations or scheduled jobs fail, when performance exceeds an agreed threshold, or when rollback has not been tested on the pilot OU.

Share this Post

Leave a Reply

Your email address will not be published. Required fields are marked *