Skip to content
This repository was archived by the owner on Sep 16, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions backend/backend/settings/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@
IS_DEV = True

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

ALLOWED_HOSTS = ['*']
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, it's needed for making it accessible from my own device (from local network) when run with docker-compose. I hope this addition won't break anything in our prod infrastructure

4 changes: 3 additions & 1 deletion backend/device_registry/api_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def post(self, request, *args, **kwargs):
device = Device.objects.get(device_id=request.device_id)
device.last_ping = timezone.now()
device.agent_version = data.get('agent_version')
device.audit_files = data.get('audit_files', [])
if 'deb_packages' in data:
deb_packages = data['deb_packages']
device.deb_packages_hash = deb_packages['hash']
Expand Down Expand Up @@ -132,7 +133,8 @@ def post(self, request, *args, **kwargs):
firewall_state.save()

device.update_trust_score = True
device.save(update_fields=['last_ping', 'agent_version', 'deb_packages_hash', 'update_trust_score'])
device.save(update_fields=['last_ping', 'agent_version', 'audit_files', 'deb_packages_hash',
'update_trust_score'])

if datastore_client:
task_key = datastore_client.key('Ping')
Expand Down
19 changes: 19 additions & 0 deletions backend/device_registry/migrations/0062_device_audit_files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 2.2.6 on 2019-10-03 06:44

import django.contrib.postgres.fields.jsonb
from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('device_registry', '0061_deviceinfo_processes'),
]

operations = [
migrations.AddField(
model_name='device',
name='audit_files',
field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=list),
),
]
20 changes: 20 additions & 0 deletions backend/device_registry/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ class Meta:
unique_together = ['name', 'version', 'arch']


SSHD_CONFIG_PARAMS_SAFE_VALUES = {
'PermitEmptyPasswords': 'no',
'PermitRootLogin': 'no',
'PasswordAuthentication': 'no',
'AllowAgentForwarding': 'no',
'Protocol': '2'
}


class Device(models.Model):
device_id = models.CharField(
max_length=128,
Expand Down Expand Up @@ -97,6 +106,17 @@ class Device(models.Model):
update_trust_score = models.BooleanField(default=False, db_index=True)
deb_packages = models.ManyToManyField(DebPackage)
deb_packages_hash = models.CharField(max_length=32, blank=True)
audit_files = JSONField(blank=True, default=list)

def sshd_issues(self):
if self.audit_files:
for file_info in self.audit_files:
if 'sshd' in file_info['name']:
issues = []
for k, v in file_info['issues'].items():
issues.append((k, v, SSHD_CONFIG_PARAMS_SAFE_VALUES[k]))
return issues
return None

@property
def certificate_expired(self):
Expand Down
70 changes: 53 additions & 17 deletions backend/device_registry/templates/device_info_security.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{% extends "admin_base.html" %}
{% load split_string %}
{% load misc %}

{% block title %}WoTT - Device Info{% endblock title %}

Expand Down Expand Up @@ -58,7 +59,7 @@ <h4 class="tab-title">Security</h4>
{% endif %}
</td>
</tr>
<tr>
<tr>
<th scope="row">
Default Credentials
<a href="https://wott.io/documentation/faq#default-credentials"
Expand All @@ -77,17 +78,52 @@ <h4 class="tab-title">Security</h4>
</td>
</tr>
<tr>
<tr>
<th scope="row">
OpenSSH Audit
</th>
<td>Coming soon!</td>
<tr>
<th scope="row">System File Audit</th>
<td>
{% if object.audit_files %}
<table class="table table-borderless table-sm">
<thead class="thead-light">
<tr>
<th scope="col">Path</th>
<th scope="col">Checksum (SHA-256)</th>
<th scope="col">Last Modified</th>
</tr>
</thead>
{% for file in object.audit_files %}
<tr>
<td>{{ file.name }}</td>
<td>{{ file.sha256 }}</td>
<td>
{% if file.last_modified %}{{ file.last_modified|fromunix|timesince }} ago{% endif %}</td>
</tr>
{% endfor %}
</table>
{% endif %}
</td>
</tr>
<tr>
<tr>
<th scope="row">
Insecure Services
</th>
<th scope="row">Configuration Audit</th>
<td>
{% with object.sshd_issues as sshd_issues %}
{% if sshd_issues %}
<h5>OpenSSH</h5>
<ul style="list-style-type:none; padding: 0;">
{% for issue in sshd_issues %}
<li>{% include "badge.html" with icon="exclamation-circle" color="danger" %} Consider
changing "{{ issue.0 }}" from "{{ issue.1 }}" to "{{ issue.2 }}"
</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
</td>
</tr>
<tr>
<tr>
<th scope="row">
Insecure Services
</th>
<td>
{% with object.insecure_services as services %}
{% if services %}
Expand All @@ -105,13 +141,13 @@ <h4 class="tab-title">Security</h4>
</td>
</tr>
<th scope="row">Logins</th>
<td>
{% if object.deviceinfo.logins %}
<pre>{{ object.deviceinfo.beautified_logins }}</pre>
{% else %}
No recent login attempts detected.
{% endif %}
</td>
<td>
{% if object.deviceinfo.logins %}
<pre>{{ object.deviceinfo.beautified_logins }}</pre>
{% else %}
No recent login attempts detected.
{% endif %}
</td>
</tr>
<tr>
<th scope="row">
Expand Down
9 changes: 9 additions & 0 deletions backend/device_registry/templatetags/misc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django import template
from django.utils import timezone

register = template.Library()


@register.filter(name='fromunix')
def fromunix(value):
return timezone.datetime.fromtimestamp(value, timezone.get_default_timezone())