Introduction
After a period of preparation, I finally achieved success. In the amateur radio A license exam for September in Heilongjiang Province, which I participated in, I obtained a perfect score and successfully obtained my own amateur radio operator's license.
Whether you're a hobby radio enthusiast or someone constantly learning, the most important thing is to be open-minded and continuously learn from others. Having fully understood this principle, I joined...HamCQ CommunityI plan to have a friendly exchange with other enthusiasts who share similar interests.
When I discovered that the community had a certification function for operating licenses, I immediately filled in my name and personal ID information to verify. The verification was successful very quickly. Because the verification process was so short, I began to suspect that it might be automated. If not, how could I access and verify the corresponding certificate? Driven by this curiosity, I started researching and documenting the process in this article.
Information gathering
After some investigation, it appears that onlyPlatform for information on amateur radio operator technical skillsAndValidation of amateur radio operator technical skills and information management system.It is possible to query for certificates. However, the "Amateur Radio Operator Skill Information Platform" provided by the Ministry of Industry and Information Technology's government service platform requires a name and mobile phone number as search criteria, and only allows queries after receiving a verification code. This does not meet the requirements for community-based verification searches.
Therefore, the amateur radio operating skills validation and information management system became the focus of this research.
The system's query conditions are name, certificate number (optional), and ID card number. These match the community search criteria. It is likely that the community verification process involves either manual querying by community administrators or the use of an interface to process and verify information. I am very interested in exploring this further.
Research process
For websites with a front-end and back-end separation, when operating data, especially for operations such as creating, deleting, updating, and querying, this is achieved by sending network requests through API interfaces.
Research requirements"Observe, inquire, and palpate"To deal with these problems, it's essential to avoid rushing and instead carefully observe before taking action. Focus on exploiting their weaknesses.
Let's start with "observing" the webpage, following the classic query sequence: "enter information," "click to search," and "receive results." The typical approach involves entering information and then clicking a search button to send a GET or POST request to the backend. After the server receives the request, it queries the database and returns data in a specific format (e.g., JSON). Each item in the list is an individual item, and the returned information is parsed by JavaScript and displayed on the page. Once you understand the principle, you can proceed to the next step: "listening."
What? You've never heard of this before? I'll try to explain it in a way that's easy to understand, but if you really want to grasp what I'm doing, you'll need to acquire some basic knowledge about the internet.
"Debugging" involves analyzing the requests sent and the data returned, to identify the API address, determine the technologies used, and analyze the required data. First, enter the correct information to simulate normal operation and view the network request's structure. Open the developer console, enter the search criteria, click "search," and luckily, a unique network request is found – this is the main focus of today's debugging.

Request for analysis
Request header
Click on the header to see that this request uses the POST method, and the API interface address is:http://82.157.138.16:8091/CRAC/app/businessSupport/cracOperationCert/getOperCertByParamWebCheck the request headers to see if there are any unencrypted parameters. Also, verify that cookies are being used to extend the session's lifespan.JSESSIONIDThis means that this interface can be accessed and used freely, without any authentication required.
accept:
*/*
accept-encoding:
gzip, deflate
accept-language:
zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
connection:
keep-alive
content-length:
114
content-type:
application/json; charset=UTF-8
cookie:
JSESSIONID=74D062BFB81FCD71961AD181B4C9D2D5
host:
82.157.138.16:8091
mm:
null
origin:
http://82.157.138.16:8091
qm:
null
referer:
http://82.157.138.16:8091/CRAC/crac/pages/list_cert.html
user-agent:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edge/129.0.0.0
x-requested-with:
XMLHttpRequest
Request body
The key difference between a POST request and a GET request is that a POST request includes a request body, rather than adding parameters to the HTTP link. Therefore, to find out what was sent when we clicked the button, we need to examine the request body.

{"req":{"page_no":"1","page_size":"100","name":"***", "certificateNo":"", "idCarNumber":"********************"}}
This request body is formatted in JSON. Let's analyze the fields:page_no: Page number,page_size: The page can display a maximum of [number] items.name: Name,certificateNoCertificate number:idCarNumber: ID number
Now that you understand the request body and its format, you can proceed with the next steps.
"Cutting" represents the moment in the research where the most creative application of interfaces is possible. I will use simple and easy-to-use Python to implement interface calls, leveraging a wide range of interface technologies.
There are many libraries in Python for making network requests, and one of the most popular and effective ones isrequestsWith just a few simple steps, you can complete the simulation of network requests. In this script, to make the code more robust, it automatically performs input validation when an input is made. The script will automatically detect whether the input is valid and provide feedback; it also automatically determines whether the request was successful. If the request is successful, the retrieved information is output to the interface.
Incorrect input result

Correct input result

The source code is as follows:
```python
import re
import requests
import json
# Chinese name regular expression
chinese_name_pattern = r'^[\u4E00-\u9FA5]{2,4}$'
# ID card regular expression
_IDRe18 = re.compile(r'^([1-6][1-9]|50)\d{4}(18|19|20)\d{2}((0[1-9])|10|11|12)(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$')
_IDre15 = re.compile(r'^([1-6][1-9]|50)\d{4}\d{2}((0[1-9])|10|11|12)(([0-2][1-9])|10|20|30|31)\d{3}$')
# Input prompt
page_no = 1
page_size = 100
while True:
name = input("Please enter the name: ")
if re.match(chinese_name_pattern, name):
break
print("Name should be 2-4 characters in Chinese, please try again.")
while True:
certificateNo = input("Enter certificate number (optional): ")
if not certificateNo:
break
pattern = r'^[ABC]\d{9}$'
if re.match(pattern, certificateNo):
break
print("Certificate number format should be ABC followed by 9 digits, please try again.")
while True:
idCarNumber = input("Enter ID card number: ")
if _IDRe18.match(idCarNumber) or _IDre15.match(idCarNumber):
break
print("ID card number format is incorrect, please try again.")
# API request
url = "http://82.157.138.16:8091/CRAC/app/businessSupport/cracOperationCert/getOperCertByParamWeb"
headers = {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
"Connection": "keep-alive",
"Content-Type": "application/json; charset=UTF-8",
"Cookie": "",
"Host": "82.157.138.16:8091",
"Origin": "http://82.157.138.16:8091",
"Referer": "http://82.157.138.16:8091/CRAC/crac/pages/list_cert.html",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0",
"X-Requested-With": "XMLHttpRequest",
"mm": "null",
"qm": "null"
}
data = {
"req": {
"page_no": page_no,
"page_size": page_size,
"name": name,
"certificateNo": certificateNo,
"idCarNumber": idCarNumber
}
}
try:
response = requests.post(url, headers=headers, json=data)
response.raise_for_status() # Check if the request was successful
except requests.exceptions.RequestException as e:
print(f"An error occurred during the request: {e}")
exit()
try:
prc_list = response.json()['res']['prcList']
except json.JSONDecodeError:
print("The response data is not a valid JSON format")
exit()
if not prc_list:
print("No related certificate information found")
exit()
# Extract useful information and format output
for item in prc_list:
print(f"ID: {item.get('id', '')}")
print(f"Name: {item.get('name', '')}")
print(f"Sex: {item.get('sex', '')}")
print(f"Category: {item.get('type', '')}")
print(f"Certificate number: {item.get('certificateNo', '')}")
print(f"Pass date: {item.get('passDate', '')}")
print(f"Pass location: {item.get('passAddr', '')}")
print(f"Issue date: {item.get('issueDate', '')}")
print(f"Issuing institution: {item.get('addr', '')}")
print("---------------------------")
```
Epilogue
Through this analysis, I found that the query interface does not have any encryption measures and is easy to call, so it is likely that the community itself uses this interface for secondary development to complete certificate verification. This analysis has allowed me to revisit the process of determining page types, simulating network requests, analyzing network requests, and performing testing, which feels very good. This was inHamCQ CommunityPosted my first message, hoping to connect with more enthusiasts in the future. 73! Goodbye!