Yarana Iot Guru
Published © MIT

🛡️ How to Build a Secure College Attendance System

A secure, tamper-resistant attendance system using ESP32 + RFID (RC522) with server-side authentication and MySQL logging. Ideal for classro

BeginnerShowcase (no instructions)8 hours9
🛡️ How to Build a Secure College Attendance System

Things used in this project

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Code

🔧 Database Setup (MySQL

C/C++
Create database & tables (example SQL):
CREATE DATABASE attendance_system;
USE attendance_system;

-- Students table
CREATE TABLE students (
  id INT AUTO_INCREMENT PRIMARY KEY,
  student_id VARCHAR(32) UNIQUE NOT NULL,    -- college roll / unique id
  name VARCHAR(100) NOT NULL,
  card_uid VARCHAR(64) UNIQUE,                -- RFID UID
  pin_hash VARCHAR(255),                      -- optional hashed PIN
  active TINYINT DEFAULT 1
);

-- Attendance logs
CREATE TABLE attendance_log (
  id INT AUTO_INCREMENT PRIMARY KEY,
  student_id VARCHAR(32) NOT NULL,
  station_id VARCHAR(50) NOT NULL,
  scan_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  method VARCHAR(20),     -- 'card','card+pin'
  raw_uid VARCHAR(64),
  ip_address VARCHAR(45),
  notes TEXT
);

-- Admin users (for dashboard)
CREATE TABLE admins (
  id INT AUTO_INCREMENT PRIMARY KEY,
  username VARCHAR(50) UNIQUE,
  password_hash VARCHAR(255)
);

🔐 Secure API: PHP Endpoint (insert_attendance.php)

C/C++
Security notes: Use HTTPS on server. Require an API key per station or sign the payload (HMAC) with a station secret. Below example shows API key check + prepared statements.
<?php
// insert_attendance.php
// POST params: api_key, station_id, card_uid, student_id (optional), method, pin_hash (optional)

$CONFIG_API_KEYS = [
  'STATION_01' => 'your_station_api_key_here' // store securely, rotate periodically
];

$servername = "localhost";
$dbuser = "root";
$dbpass = "";
$dbname = "attendance_system";

$input = $_POST;

// Basic validation
if (!isset($input['api_key'], $input['station_id'], $input['card_uid'])) {
  http_response_code(400);
  echo json_encode(['status'=>'error','msg'=>'Missing parameters']);
  exit;
}

$api_key = $input['api_key'];
$station_id = $input['station_id'];
$card_uid = $input['card_uid'];
$method = isset($input['method']) ? $input['method'] : 'card';
$pin_hash = isset($input['pin_hash']) ? $input['pin_hash'] : null;

// Verify API key -> station mapping
$valid = false;
foreach ($CONFIG_API_KEYS as $sid => $key) {
  if ($sid === $station_id && hash_equals($key, $api_key)) { $valid = true; break; }
}
if (!$valid) {
  http_response_code(403);
  echo json_encode(['status'=>'error','msg'=>'Invalid API key']);
  exit;
}

// DB connect
$conn = new mysqli($servername, $dbuser, $dbpass, $dbname);
if ($conn->connect_error) {
  http_response_code(500);
  echo json_encode(['status'=>'error','msg'=>'DB connection failed']);
  exit;
}

// Find student by card_uid
$stmt = $conn->prepare("SELECT student_id, name, pin_hash FROM students WHERE card_uid = ? AND active = 1 LIMIT 1");
$stmt->bind_param("s", $card_uid);
$stmt->execute();
$res = $stmt->get_result();
if ($res->num_rows === 0) {
  // Unknown card
  echo json_encode(['status'=>'unknown','msg'=>'Card not registered']);
  $stmt->close();
  $conn->close();
  exit;
}
$row = $res->fetch_assoc();
$student_id = $row['student_id'];
$student_name = $row['name'];
$db_pin_hash = $row['pin_hash'];
$stmt->close();

// Optional: if method == 'card+pin', verify pin_hash matches stored hash
if ($method === 'card+pin') {
  if (!$pin_hash || !password_verify($pin_hash, $db_pin_hash)) {
    echo json_encode(['status'=>'error','msg'=>'Invalid PIN']);
    $conn->close();
    exit;
  }
}

// Insert attendance log
$ip = $_SERVER['REMOTE_ADDR'];
$stmt2 = $conn->prepare("INSERT INTO attendance_log (student_id, station_id, method, raw_uid, ip_address, notes) VALUES (?, ?, ?, ?, ?, ?)");
$notes = "Name: " . $student_name;
$stmt2->bind_param("ssssss", $student_id, $station_id, $method, $card_uid, $ip, $notes);
$ok = $stmt2->execute();
$stmt2->close();
$conn->close();

if ($ok) {
  echo json_encode(['status'=>'ok','msg'=>'Attendance recorded','student'=> $student_name, 'student_id'=>$student_id]);
} else {
  http_response_code(500);
  echo json_encode(['status'=>'error','msg'=>'DB insert failed']);
}
?>

🧠 ESP32 Code (Read RFID & send secure POST)

C/C++
This example:

Reads RFID UID,

Computes short HMAC signature (station secret) for authenticity,

Sends POST to API.
/*
 Secure Attendance - ESP32 + RC522
 Author: YaranaIoT Guru
*/

#include <WiFi.h>
#include <HTTPClient.h>
#include <MFRC522.h>
#include <SPI.h>
#include <mbedtls/md.h> // for HMAC (ESP32 core includes mbedtls)

#define RST_PIN 22
#define SS_PIN 21

// Edit these
const char* ssid = "YourWiFi";
const char* password = "YourPassword";

const char* serverUrl = "https://yourserver.com/attendance/insert_attendance.php";
const char* stationId = "STATION_01";
const char* stationApiKey = "your_station_api_key_here"; // used for simple API key auth

MFRC522 mfrc522(SS_PIN, RST_PIN);

void setup() {
  Serial.begin(115200);
  SPI.begin(); 
  mfrc522.PCD_Init();
  delay(100);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi");
  while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
  Serial.println("\nConnected: " + WiFi.localIP().toString());
  Serial.println("Ready, scan card...");
}

String uidToString(MFRC522::Uid uid) {
  String s = "";
  for (byte i=0; i < uid.size; i++) {
    if(uid.uidByte[i] < 0x10) s += "0";
    s += String(uid.uidByte[i], HEX);
  }
  s.toUpperCase();
  return s;
}

// Optional: generate simple HMAC-SHA256 signature (if server expects it)
String hmac_sha256_hex(const String &key, const String &data) {
  const unsigned char *keyBuf = (const unsigned char *)key.c_str();
  size_t keyLen = key.length();
  const unsigned char *dataBuf = (const unsigned char *)data.c_str();
  size_t dataLen = data.length();
  unsigned char output[32];
  mbedtls_md_context_t ctx;
  const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
  mbedtls_md_init(&ctx);
  mbedtls_md_setup(&ctx, md_info, 1);
  mbedtls_md_hmac_starts(&ctx, keyBuf, keyLen);
  mbedtls_md_hmac_update(&ctx, dataBuf, dataLen);
  mbedtls_md_hmac_finish(&ctx, output);
  mbedtls_md_free(&ctx);
  // convert to hex
  char hexStr[65];
  for (int i=0; i<32; i++) sprintf(hexStr + (i*2), "%02x", output[i]);
  hexStr[64]=0;
  return String(hexStr);
}

void loop() {
  // Look for new cards
  if ( ! mfrc522.PICC_IsNewCardPresent()) return;
  if ( ! mfrc522.PICC_ReadCardSerial()) return;

  String uid = uidToString(mfrc522.uid);
  Serial.println("Card UID: " + uid);

  // payload data; include timestamp if desired
  String payload = "station_id=" + String(stationId) + "&card_uid=" + uid;

  // Option A: simple API key auth (POST field)
  HTTPClient http;
  http.begin(serverUrl);
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");
  String postData = "api_key=" + String(stationApiKey) + "&station_id=" + String(stationId) + "&card_uid=" + uid + "&method=card";
  int httpCode = http.POST(postData);

  if (httpCode > 0) {
    String resp = http.getString();
    Serial.println("Server response: " + String(httpCode) + " - " + resp);
  } else {
    Serial.println("HTTP failed: " + String(httpCode));
  }
  http.end();

  // feedback
  // buzzer/LED logic here

  delay(1500); // debounce
}

Credits

Yarana Iot Guru
15 projects • 0 followers
Yarana Iot Guru Yarana IoT Guru: Arduino, ESP32, GSM, NodeMCU & more. Projects, Tutorials & App Development. Innovate with us!
Thanks to YaranaIoT Guru.

Comments