Social Engineering & Phishing
The easiest way into a company is often not through its firewall but through its people. Social engineering means manipulating someone into doing something that helps an attacker: clicking a link, sharing an OTP, approving a payment or holding a door open. It works because it targets normal human instincts such as helpfulness, fear and respect for authority.
In this lesson you will learn the common social engineering attacks, including scams that are widespread in India, the psychological tricks behind them, how to spot red flags in links and email headers, and the technical and process defences that protect people. This lesson is about recognising and defending against these attacks, never about running them.
The psychology behind it
Almost every scam pulls one or more of these levers:
- Urgency: "Your account will be blocked in 2 hours."
- Authority: a message that appears to come from the CEO, a bank, the police or a government department.
- Fear: "A case has been registered against your Aadhaar number."
- Greed or reward: "You have won a cashback of ₹5,000", "Earn ₹3,000 a day liking videos."
- Curiosity: "Salary revision list 2026.xlsx".
- Helpfulness: a caller from "IT support" who needs your password to fix a problem.
Training people to notice the feeling of pressure ("why am I being rushed?") is one of the most effective defences.
Types of social engineering
| Attack | Channel | Typical example |
|---|---|---|
| Phishing | Fake bank or courier email with a login link | |
| Spear phishing | Email, targeted | A message to Meera in accounts mentioning her real manager and a real project |
| Whaling | Email to senior leaders | Fake legal notice sent to a company director |
| Business email compromise (BEC) | Email from a real or look-alike account | "Our bank details have changed, please pay this invoice to the new account" |
| Smishing | SMS | "Your electricity will be disconnected tonight, call this number" |
| Vishing | Voice call | Fake bank officer asking for the OTP "to stop a fraudulent transaction" |
| Quishing | QR codes | A sticker over a shop's real QR code, or a QR in an email leading to a fake login |
| Pretexting | Any | A made-up story, such as a "vendor audit", to collect information |
| Baiting | Physical | A USB drive labelled "Exam papers" left in a college lab |
| Tailgating | Physical | Following an employee through a secure door |
Scams frequently reported in India include fake KYC-update messages, UPI "collect requests" (you never need to enter your UPI PIN to receive money), fake customer care numbers found through search results, part-time "task" job scams on messaging apps, and "digital arrest" calls where criminals pose as police or investigators on a video call and demand money. There is no procedure called "digital arrest" in Indian law; real agencies do not arrest or settle cases over video calls.
Spotting red flags in links
Attackers register domains that look like real ones: extra words (sbi-kyc-update.example), swapped letters, different top-level domains, or homoglyphs, characters from other alphabets that look identical. Browsers show such internationalised domains in an encoded form starting with xn-- (called punycode). This checker looks for common warning signs:
import ipaddress
from urllib.parse import urlsplit
TRUSTED = {"onlinesbi.sbi", "incometax.gov.in", "shop.example"}
def red_flags(url):
flags = []
parts = urlsplit(url)
host = (parts.hostname or "").lower()
if parts.scheme != "https":
flags.append("not HTTPS")
if "@" in parts.netloc:
flags.append("'@' in address hides the real host")
try:
ipaddress.ip_address(host)
flags.append("raw IP address instead of a name")
except ValueError:
pass
if any(label.startswith("xn--") for label in host.split(".")):
flags.append("punycode: looks like " + host.encode().decode("idna"))
if host not in TRUSTED and any(t.split(".")[0] in host for t in TRUSTED):
flags.append("brand name inside an untrusted domain")
if host.count(".") >= 4:
flags.append("many subdomains")
return flags or ["no obvious red flags (still verify the sender)"]
for url in ["https://onlinesbi.sbi/login",
"http://onlinesbi.kyc-verify.example.in/update",
"https://incometax.gov.in@203.0.113.9/refund",
"https://xn--shp-ted.example/offers"]:
print(url)
for f in red_flags(url):
print(" -", f)https://onlinesbi.sbi/login - no obvious red flags (still verify the sender) http://onlinesbi.kyc-verify.example.in/update - not HTTPS - brand name inside an untrusted domain https://incometax.gov.in@203.0.113.9/refund - '@' in address hides the real host - raw IP address instead of a name https://xn--shp-ted.example/offers - punycode: looks like shоp.example
In the third link, everything before the @ is treated as a user name, so the browser actually goes to 203.0.113.9. In the last one, the "o" in shоp is a Cyrillic letter, so the domain only looks like shop.example. No checker is perfect: the safest habit is to never log in through a link in a message, and instead type the address or use the official app.
Email authentication: SPF, DKIM and DMARC
The From: address in an email is just text and is easy to forge. Three DNS-based standards let receiving servers check whether a message really came from the domain it claims:
- SPF: a TXT record listing the servers allowed to send mail for the domain.
- DKIM: the sending server signs each message; the public key is published in DNS.
- DMARC: a TXT record at
_dmarc.yourdomaintelling receivers what to do when SPF or DKIM checks fail and the domain does not align:p=none(only report),p=quarantine(spam folder) orp=reject(refuse). It also asks for reports, so you learn who is sending mail as you.
Check your own domain's records:
dig +short TXT yourdomain.in
dig +short TXT _dmarc.yourdomain.inA strong setup ends with a DMARC policy such as v=DMARC1; p=reject; rua=mailto:dmarc-reports@yourdomain.in. Receiving servers record their checks in an Authentication-Results header, which you can read with Python's built-in email module:
from email import message_from_string
raw = """From: "SBI Alerts" <alerts@sbi-secure-kyc.example>
Reply-To: helpdesk.kyc2026@freemail.example
To: kabir@shop.example
Subject: URGENT: KYC expires today, account will be blocked
Authentication-Results: mx.shop.example; spf=fail smtp.mailfrom=sbi-secure-kyc.example; dkim=none; dmarc=fail header.from=sbi-secure-kyc.example
Dear customer, update your KYC within 2 hours using the link below."""
msg = message_from_string(raw)
results = msg["Authentication-Results"]
checks = {part.split("=")[0].strip(): part.split("=")[1].split()[0] for part in results.split(";")[1:]}
print("Subject:", msg["Subject"])
for name in ["spf", "dkim", "dmarc"]:
print(f" {name.upper():<6} {checks.get(name, 'missing')}")
from_domain = msg["From"].split("@")[-1].rstrip(">")
reply_domain = msg["Reply-To"].split("@")[-1]
if from_domain != reply_domain:
print(f" Replies go to a different domain: {reply_domain}")
if any(word in msg["Subject"].lower() for word in ["urgent", "blocked", "expires"]):
print(" Pressure words in the subject line")Subject: URGENT: KYC expires today, account will be blocked SPF fail DKIM none DMARC fail Replies go to a different domain: freemail.example Pressure words in the subject line
Note that a phishing domain can pass SPF, DKIM and DMARC for its own look-alike domain. These checks prove where mail came from, not that the sender is honest.
Process defences
Technology cannot stop every trick, so organisations add simple rules:
- Call-back verification: any request to change bank details or make an urgent payment is confirmed by calling a number already on file, never a number in the email.
- Two-person approval for large payments.
- Never share OTPs or passwords, with anyone, including people claiming to be from IT or the bank.
- Phishing-resistant MFA (passkeys, security keys) so stolen passwords and OTPs are useless.
- Easy reporting: a "Report phishing" button and a team that thanks people for reporting, even false alarms.
- Awareness training and phishing simulations, run only by the organisation itself, with management approval and care for staff dignity.
As a citizen, report cyber fraud at cybercrime.gov.in or call 1930, and report suspected fraud calls and messages through the Chakshu facility on the government's Sanchar Saathi portal.
Common mistakes
- Trusting the display name. "SBI Alerts" can be typed by anyone; look at the actual address and domain.
- Clicking links in messages to log in. Type the address or use the official app instead.
- Believing the padlock. Phishing sites use HTTPS too.
- Blaming people who fall for phishing. Shame stops reporting; fast reporting limits damage.
- Leaving DMARC at
p=nonefor ever. Move toquarantineand thenrejectonce legitimate senders are covered.
Key points
- Social engineering exploits urgency, authority, fear, greed, curiosity and helpfulness.
- Know the forms: phishing, spear phishing, BEC, smishing, vishing, quishing, pretexting, baiting and tailgating.
- Look-alike domains,
@tricks, raw IPs and punycode are common red flags in links. - SPF, DKIM and DMARC (ideally
p=reject) make domain spoofing much harder. - Call-back verification, never sharing OTPs, phishing-resistant MFA and easy reporting are key defences.
- Report fraud at cybercrime.gov.in or 1930; there is no such thing as a "digital arrest".
Exercise
Add a new rule to red_flags(): flag URLs whose path or query contains words often used in scams, such as kyc, refund, reward or verify. Test it with https://shop.example/account/verify-kyc?reward=5000 and https://shop.example/products.
Show solution
from urllib.parse import urlsplit
SCAM_WORDS = ["kyc", "refund", "reward", "verify"]
def word_flags(url):
parts = urlsplit(url)
text = (parts.path + "?" + parts.query).lower()
found = [w for w in SCAM_WORDS if w in text]
return f"scam words: {', '.join(found)}" if found else "no scam words"
for url in ["https://shop.example/account/verify-kyc?reward=5000", "https://shop.example/products"]:
print(url, "->", word_flags(url))The first URL shows scam words: kyc, reward, verify. On a trusted domain this is a hint, not proof, so combine it with the other checks before deciding.
Quick Quiz
1. An email from your "managing director" asks you to urgently pay a new vendor account. What is the best response?
Call-back verification on a known number defeats business email compromise.
2. What does a DMARC policy of p=reject tell receiving mail servers?
p=reject asks receivers to refuse mail that fails SPF/DKIM alignment.
3. A link reads https://incometax.gov.in@203.0.113.9/refund. Where does it really go?
Everything before the @ is treated as a user name; the host is the IP address after it.
4. Which statement about "digital arrest" calls is true?
Real agencies do not arrest people or settle cases over video calls.
Learn Cyber Security with a mentor
Free lessons get you started. Our Ethical Hacking & Cyber Security training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
