
Temukan titik lemahnya.
Perbaiki terlebih dahulu.
Masukkan situs web atau IP untuk membuat laporan keamanan terfokus dengan temuan yang diprioritaskan dan perbaikan praktis.
SIAP KAPAN PUN ANDA SIAP
Mulai dengan target
Laporan Anda akan mengatur sinyal risiko yang terlihat dan langkah selanjutnya yang disarankan di satu tempat.
Sedang menyusun laporan Anda…
Meninjau sinyal targetTinjau nomor tersebut.
Perkuat akun.
Masukkan nomor telepon untuk membuat simulasi keamanan lokal dengan konteks operator, skor risiko, dan tindakan praktis.
SIMULASI LOKAL SIAP
Mulai dengan nomor
Dapatkan tampilan ringkas konteks operator, kekuatan pemulihan, dan tindakan perlindungan akun.
Menghasilkan simulasi…
Menghitung sinyal risiko demo secara lokalOperasikan tampilan.
Perhatikan sinyalnya.
Buka dasbor manajemen perangkat yang didukung oleh respons WebSocket langsung.
SIAGA SESI
Buka sesi perangkat
Gunakan kolom di atas untuk melihat data perangkat yang dikembalikan oleh WebSocket.
Pengiriman
Siapkan tautan APK dan kode QR secara lokal untuk perangkat resmi.
Kirim melalui Email
Kirim tautan APK yang dibuat melalui layanan pengiriman.
Kirim melalui SMS Twilio
Kirim tautan APK yang dibuat melalui layanan pengiriman Twilio.
Kirim melalui Webhook
Kirim tautan APK yang dihasilkan ke platform webhook.
PENGIRIMAN KODE QR
Pengiriman Kode QR
Biarkan perangkat resmi memindai tautan APK yang dibuat.
iTarget memindai kode QR dengan kamera ponsel mereka untuk mengunduh APK.
Referensi server backend
Terapkan server.js secara terpisah, lalu ganti kredensial layanan placeholder sebelum menghubungkan backend produksi.
const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const cors = require('cors');
const twilio = require('twilio');
const sgMail = require('@sendgrid/mail');
const app = express();
app.use(cors());
app.use(express.json());
const server = http.createServer(app);
const io = new Server(server, { cors: { origin: '*' } });
// Store connected clients
const clients = new Map();
// Twilio setup (replace with your credentials)
const twilioClient = twilio('ACCOUNT_SID', 'AUTH_TOKEN');
// SendGrid setup
sgMail.setApiKey('SENDGRID_API_KEY');
// WebSocket connection
io.on('connection', (socket) => {
console.log('Client connected:', socket.id);
socket.on('register', (phoneNumber) => {
clients.set(phoneNumber, socket);
socket.emit('registered', { status: 'ok', phone: phoneNumber });
});
socket.on('command_response', (data) => {
io.emit('command_result', data);
});
socket.on('disconnect', () => {
for (let [phone, sock] of clients.entries()) {
if (sock.id === socket.id) {
clients.delete(phone);
break;
}
}
});
});
// API endpoint to send SMS via Twilio
app.post('/api/send-sms', async (req, res) => {
const { to, message } = req.body;
try {
await twilioClient.messages.create({ body: message, from: 'YOUR_TWILIO_NUMBER', to });
res.json({ status: 'sent' });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// API endpoint to send email via SendGrid
app.post('/api/send-email', async (req, res) => {
const { email, subject, message } = req.body;
try {
await sgMail.send({ to: email, from: '[email protected]', subject, html: message });
res.json({ status: 'sent' });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// API endpoint to send webhook messages
app.post('/api/send-webhook', async (req, res) => {
const { url, payload } = req.body;
try {
const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) });
res.json({ status: 'sent', response: response.status });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// API endpoint to relay commands to mobile client
app.post('/api/command', (req, res) => {
const { phone, command, params } = req.body;
const clientSocket = clients.get(phone);
if (!clientSocket) return res.status(404).json({ error: 'Client not connected' });
clientSocket.emit('command', { command, params });
res.json({ status: 'sent' });
});
server.listen(3000, () => console.log('Server running on port 3000'));
Referensi klien Android yang mengutamakan persetujuan
Referensi ini adalah kerangka pendamping kontrol orang tua yang aman: memerlukan persetujuan eksplisit, menggunakan notifikasi latar depan yang terlihat, hanya terhubung melalui TLS, mendukung pemutusan koneksi dan mulai otomatis dengan keikutsertaan, serta mencatat jejak audit.
Streaming kamera atau mikrofon jarak jauh, pengumpulan SMS dan log panggilan, penjelajahan file sembarangan, dan penguncian perangkat secara diam-diam sengaja tidak diimplementasikan. Gunakan alur izin yang terlihat dan dimulai oleh pengguna serta pemilih sistem Android untuk fitur apa pun di masa mendatang.
Ganti URL server dan penyediaan token, tambahkan dependensi Socket.IO Android, dan tinjau aturan layanan latar depan Android saat ini sebelum penerapan. Sampel hanya menerima perintah ping yang tidak berbahaya.
// MainActivity.kt
package com.example.remotecontrol
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.widget.Button
import android.widget.CheckBox
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import io.socket.client.IO
import io.socket.client.Socket
import org.json.JSONObject
class MainActivity : AppCompatActivity() {
private lateinit var socket: Socket
private lateinit var audit: AuditLog
private lateinit var status: TextView
private val prefs by lazy { getSharedPreferences("parental_control", MODE_PRIVATE) }
private val serverUrl = "https://your-domain.example"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
audit = AuditLog(this)
setContentView(buildConsentScreen())
}
private fun buildConsentScreen(): LinearLayout {
val root = LinearLayout(this).apply { orientation = LinearLayout.VERTICAL; setPadding(32, 48, 32, 32) }
val title = TextView(this).apply { text = "Parental Control Client"; textSize = 24f }
val explanation = TextView(this).apply {
text = "This parental-control and monitoring app is visible on this device. No monitoring starts until the device user agrees. The safe demo exchanges audit events and ping acknowledgements only."
}
val consent = CheckBox(this).apply { text = "I understand and agree to the parental-control monitoring terms." }
val autoStart = CheckBox(this).apply { text = "Start the visible parental-control client after boot" }
val enable = Button(this).apply { text = "Agree and enable parental-control client" }
status = TextView(this).apply { text = "Not connected" }
val disconnect = Button(this).apply { text = "Disconnect"; isEnabled = false }
root.addView(title); root.addView(explanation); root.addView(consent); root.addView(autoStart)
root.addView(enable); root.addView(status); root.addView(disconnect)
enable.setOnClickListener {
if (!consent.isChecked) { status.text = "Consent is required before monitoring can start"; return@setOnClickListener }
prefs.edit().putBoolean("consent", true).putBoolean("auto_start", autoStart.isChecked).apply()
requestNotificationPermission()
ContextCompat.startForegroundService(this, Intent(this, ForegroundService::class.java))
connect()
disconnect.isEnabled = true
}
disconnect.setOnClickListener { disconnect() }
return root
}
private fun requestNotificationPermission() {
if (Build.VERSION.SDK_INT >= 33 && ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.POST_NOTIFICATIONS), 41)
}
}
private fun connect() {
if (!prefs.getBoolean("consent", false)) return
val token = prefs.getString("auth_token", "") ?: ""
if (token.isBlank()) { status.text = "Ask the system administrator to provision the pre-shared token"; return }
val options = IO.Options().apply { forceNew = true; reconnection = true; query = "token=$token" }
socket = IO.socket(serverUrl, options)
socket.on(Socket.EVENT_CONNECT) { runOnUiThread { status.text = "Connected over TLS/WSS" } }
socket.on("command") { args ->
val data = args.firstOrNull() as? JSONObject ?: return@on
val command = data.optString("command")
audit.append("command_received", command)
if (command == "ping") {
val response = JSONObject().put("type", "ping").put("status", "acknowledged")
audit.append("data_sent", "ping acknowledgement")
socket.emit("command_response", response)
} else {
audit.append("command_rejected", command)
socket.emit("command_response", JSONObject().put("type", "error").put("error", "Unsupported command"))
}
}
socket.connect()
audit.append("session", "connected")
}
private fun disconnect() {
if (::socket.isInitialized) socket.disconnect()
stopService(Intent(this, ForegroundService::class.java))
audit.append("session", "disconnected")
status.text = "Disconnected"
}
override fun onDestroy() { if (::socket.isInitialized) socket.disconnect(); super.onDestroy() }
}
private class AuditLog(private val activity: MainActivity) {
fun append(event: String, detail: String) {
val line = "${System.currentTimeMillis()}|$event|$detail"
val old = activity.getSharedPreferences("parental_control_audit", 0).getString("events", "") ?: ""
activity.getSharedPreferences("parental_control_audit", 0).edit().putString("events", (old + line + "\n").takeLast(100_000)).apply()
}
}
// ForegroundService.kt
package com.example.remotecontrol
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Intent
import android.os.Build
import android.os.IBinder
import androidx.core.app.NotificationCompat
class ForegroundService : Service() {
override fun onCreate() {
super.onCreate()
val manager = getSystemService(NotificationManager::class.java)
if (Build.VERSION.SDK_INT >= 26) manager.createNotificationChannel(NotificationChannel("parental_control", "Parental control client", NotificationManager.IMPORTANCE_LOW))
val open = PendingIntent.getActivity(this, 0, Intent(this, MainActivity::class.java), PendingIntent.FLAG_IMMUTABLE)
val notification: Notification = NotificationCompat.Builder(this, "parental_control")
.setSmallIcon(android.R.drawable.ic_lock_idle_lock)
.setContentTitle("Parental Control Client is active")
.setContentText("Monitoring is visible and can be disconnected from the app")
.setContentIntent(open)
.setOngoing(true)
.build()
startForeground(7, notification)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int) = START_NOT_STICKY
override fun onBind(intent: Intent?): IBinder? = null
}
// DeviceAdminReceiver.kt
package com.example.remotecontrol
import android.app.admin.DeviceAdminReceiver
class DeviceAdminReceiver : DeviceAdminReceiver()
// BootReceiver.kt — only starts after the user enabled the setting.
package com.example.remotecontrol
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.core.content.ContextCompat
class BootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == Intent.ACTION_BOOT_COMPLETED && context.getSharedPreferences("parental_control", 0).getBoolean("auto_start", false) && context.getSharedPreferences("parental_control", 0).getBoolean("consent", false)) {
ContextCompat.startForegroundService(context, Intent(context, ForegroundService::class.java))
}
}
}
// AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application android:theme="@style/Theme.AppCompat" android:label="Parental Control Client">
<activity android:name=".MainActivity" android:exported="true">
<intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter>
</activity>
<service android:name=".ForegroundService" android:exported="false" android:foregroundServiceType="dataSync" />
<receiver android:name=".DeviceAdminReceiver" android:permission="android.permission.BIND_DEVICE_ADMIN" android:exported="true" />
<receiver android:name=".BootReceiver" android:enabled="true" android:exported="false">
<intent-filter><action android:name="android.intent.action.BOOT_COMPLETED" /></intent-filter>
</receiver>
</application>
</manifest>