@appsensorlike/appsensorlike
Version:
A port of OWASP AppSensor reference implementation
601 lines (600 loc) • 25.1 kB
TypeScript
import { AccessController, Action, Role } from './accesscontrol/accesscontrol.js';
import { AttackAnalysisEngine, EventAnalysisEngine, ResponseAnalysisEngine } from './analysis/analysis.js';
import { ClientConfiguration } from './configuration/client/client_configuration.js';
import { ServerConfiguration } from './configuration/server/server_configuration.js';
import { SearchCriteria } from './criteria/criteria.js';
import { EventManager } from './event/event.js';
import { GeoLocation, GeoLocator } from './geolocation/geolocation.js';
import { ResponseHandler, UserManager } from './response/response.js';
import { Rule } from './rule/rule.js';
import { AttackStore, EventStore, ResponseStore } from './storage/storage.js';
/**
* ObjectValidationError is thrown when validation of an object fails.
*/
declare class ObjectValidationError extends Error {
invalidObj: Object;
/**
* @param message the error message
* @param invalidObj reference to the checked object
*/
constructor(message: string, invalidObj: Object);
}
/**
* Implemented by classes which want to check equality of instances of the same class
*/
interface IEquals {
/**
* Check the equality of this object and the passed object
* @param obj object to check equality on
*/
equals(obj: Object | null | undefined): boolean;
}
/**
* Context dependent checks and initialization of an object.
*/
interface IValidateInitialize {
/**
* Context dependent checks and initialization.
* Applied when: loading an object from DB's tabls; after JSON.parse.
* This is an additional check and initialization to JSON schema validation,
* in case of configuration object.
*/
checkValidInitialize(): void;
}
/**
* Base class for the most of the following classes
*/
declare class AppsensorEntity implements IEquals, IValidateInitialize {
protected id?: string | undefined;
getId(): string | undefined;
setId(id: string | undefined): void;
equals(obj: Object | null | undefined): boolean;
checkValidInitialize(): void;
}
/**
* Represent a (key, value) pair.
* It could store application specific information.
*/
declare class KeyValuePair extends AppsensorEntity {
private key;
private value;
constructor(key?: string, value?: string);
getKey(): string;
setKey(key: string): void;
getValue(): string;
setValue(value: string): void;
equals(other: Object | null): boolean;
checkValidInitialize(): void;
}
/**
* Interval units
*/
declare enum INTERVAL_UNITS {
"MILLISECONDS" = "milliseconds",
"SECONDS" = "seconds",
"MINUTES" = "minutes",
"HOURS" = "hours",
"DAYS" = "days"
}
/**
* The Interval represents a span of time.
*
* <ul>
* <li>duration (example: 15)</li>
* <li>unit: (example: minutes)</li>
* </ul>
*
*/
declare class Interval extends AppsensorEntity {
/**
* Duration portion of interval, ie. '3' if you wanted
* to represent an interval of '3 minutes'
*/
private duration;
/**
* Unit portion of interval, ie. 'minutes' if you wanted
* to represent an interval of '3 minutes'.
* Constants are provided in the Interval class for the
* units supported by the reference implementation, ie.
* SECONDS, MINUTES, HOURS, DAYS.
*/
private unit;
constructor(duration?: number, unit?: INTERVAL_UNITS);
getDuration(): number;
setDuration(duration: number): Interval;
getUnit(): string;
setUnit(unit: INTERVAL_UNITS): Interval;
toMillis(): number;
equals(obj: Object | null): boolean;
checkValidInitialize(): void;
}
/**
* The Threshold represents a number of occurrences over a span of time.
*
* <ul>
* <li>count: (example: 12)</li>
* <li>interval: (example: 15 minutes)</li>
* </ul>
*
*/
declare class Threshold extends AppsensorEntity {
/** The count at which this threshold is triggered. */
private count;
/**
* The time frame within which 'count' number of actions has to be detected in order to
* trigger this threshold.
*/
private interval;
constructor(count?: number, interval?: Interval | null);
getCount(): number;
setCount(count: number): Threshold;
getInterval(): Interval | null;
setInterval(interval: Interval | null): Threshold;
equals(obj: Object | null): boolean;
checkValidInitialize(): void;
}
/**
* After an {@link Attack} has been determined to have occurred, a Response
* is executed. The Response configuration is done on the server-side, not
* the client application.
*/
declare class Response extends AppsensorEntity {
/** {@link User} the response is for */
private user?;
/** When the event occurred */
private timestamp?;
/** String representing response action name */
private action;
/** {@link Interval} response should last for, if applicable. Ie. block access for 30 minutes */
private interval?;
/** Client application name that response applies to. */
private detectionSystem?;
/** Represent extra metadata, anything client wants to send */
private metadata?;
private active?;
/** ADDITION TO THE ORIGINAL CODE TO TRACE WHAT CAUSED THIS RESPONSE
* ESSENTIAL FOR REPORTING
* {@link DetectionPoint} that was triggered */
private detectionPoint?;
/** ADDITION TO THE ORIGINAL CODE TO TRACE WHAT CAUSED THIS RESPONSE
* ESSENTIAL FOR REPORTING
* {@link Rule} that was triggered */
private rule?;
constructor(user?: User | null | undefined, action?: string, timestamp?: Date | undefined, detectionSystem?: DetectionSystem | null | undefined, interval?: Interval | null | undefined);
getUser(): User | null | undefined;
setUser(user: User | null | undefined): Response;
getTimestamp(): Date | undefined;
setTimestamp(timestamp: Date | undefined): Response;
getAction(): string;
setAction(action: string): Response;
getInterval(): Interval | null | undefined;
setInterval(interval: Interval | null | undefined): Response;
getDetectionSystem(): DetectionSystem | null | undefined;
setDetectionSystem(detectionSystem: DetectionSystem | null | undefined): Response;
getMetadata(): KeyValuePair[] | undefined;
setMetadata(metadata: KeyValuePair[]): void;
isActive(): boolean;
getDetectionPoint(): DetectionPoint | null | undefined;
setDetectionPoint(detectionPoint: DetectionPoint | null): Response;
getRule(): Rule | null | undefined;
setRule(rule: Rule | null): Response;
equals(obj: Object | null): boolean;
checkValidInitialize(): void;
}
/**
* Detection point category
*/
declare class Category {
static REQUEST: string;
static AUTHENTICATION: string;
static SESSION_MANAGEMENT: string;
static ACCESS_CONTROL: string;
static INPUT_VALIDATION: string;
static OUTPUT_ENCODING: string;
static COMMAND_INJECTION: string;
static FILE_IO: string;
static HONEY_TRAP: string;
static USER_TREND: string;
static SYSTEM_TREND: string;
static REPUTATION: string;
}
/**
* The detection point represents the unique sensor concept in the code.
*
* A list of project detection points are maintained at https://www.owasp.org/index.php/AppSensor_DetectionPoints
*
* @see <a href="https://www.owasp.org/index.php/AppSensor_DetectionPoints">https://www.owasp.org/index.php/AppSensor_DetectionPoints</a>
*/
declare class DetectionPoint extends AppsensorEntity {
protected guid?: string | undefined;
/**
* Category identifier for the detection point. (ex. "Request", "AccessControl", "SessionManagement")
*/
private category;
/**
* Identifier for the detection point. (ex. "IE1", "RE2")
*/
private label?;
/**
* {@link Threshold} for determining whether given detection point (associated {@link AppSensorEvent})
* should be considered an {@link Attack}.
*/
private threshold;
/**
* Set of {@link Response}s associated with given detection point.
*/
private responses;
constructor(category?: string, label?: string | undefined, threshold?: Threshold | null, responses?: Response[], guid?: string | undefined);
getCategory(): string;
getLabel(): string | undefined;
setLabel(label: string | undefined): DetectionPoint;
getGuid(): string | undefined;
setGuid(guid: string): void;
getThreshold(): Threshold | null;
setThreshold(threshold: Threshold | null): DetectionPoint;
getResponses(): Response[];
setResponses(responses: Response[]): DetectionPoint;
typeMatches(other: DetectionPoint): boolean;
typeAndThresholdMatches(other: DetectionPoint): boolean;
equals(obj: Object | null): boolean;
checkValidInitialize(): void;
}
/**
* The IP Address for the user, optionally provided by the client application.
*/
declare class IPAddress extends AppsensorEntity {
private address;
private geoLocation;
constructor(address?: string, geoLocation?: GeoLocation | null);
static localhostToAddress(address: string): string;
static fromString(ipString: string, geoLocator?: GeoLocator | null): Promise<IPAddress>;
setAddress(address: string): IPAddress;
getAddress(): string;
getGeoLocation(): GeoLocation | null;
setGeoLocation(geoLocation: GeoLocation | null): IPAddress;
equalAddress(otherAddress: string): boolean;
equals(obj: Object | null): boolean;
checkValidInitialize(): void;
}
/**
* Identifier label for the system that detected the event.
* This will be either the client application, or possibly an external
* detection system, such as syslog, a WAF, network IDS, etc.
*/
declare class DetectionSystem extends AppsensorEntity {
private detectionSystemId;
private ipAddress;
constructor(detectionSystemId?: string, ipAddress?: IPAddress | null);
getDetectionSystemId(): string;
setDetectionSystemId(detectionSystemId: string): DetectionSystem;
getIPAddress(): IPAddress | null;
setIPAddress(ipAddress: IPAddress | null): DetectionSystem;
equals(obj: Object | null): boolean;
checkValidInitialize(): void;
}
/**
* The standard User object. This represents the end user in the system,
* NOT the client application.
*
* The base implementation assumes the username is provided by the client application.
*
* It is up to the client application to manage the username.
* The username could be anything, an actual username, an IP address,
* or any other identifier desired. The core notion is that any desired
* correlation on the user is done by comparing the username.
*/
declare class User extends AppsensorEntity {
static ANONYMOUS_USER: string;
static UNDEFINED_USER: string;
private username;
private ipAddress;
constructor(username?: string, ipAddress?: IPAddress | null);
getUsername(): string;
setUsername(username: string): User;
getIPAddress(): IPAddress | null;
setIPAddress(ipAddress: IPAddress | null): User;
equals(obj: Object | null | undefined): boolean;
checkValidInitialize(): void;
}
/**
* Resource represents a generic component of an application. In many cases,
* it would represent a URL, but it could also presumably be used for something
* else, such as a specific object, function, or even a subsection of an application, etc.
*/
declare class Resource extends AppsensorEntity {
/**
* The resource being requested when a given event/attack was triggered, which can be used
* later to block requests to a given function. In this implementation,
* the current request URI is used.
*/
private location;
/**
* The method used to request the resource. In terms of HTTP this would be GET/POST/PUT/etc.
* In the case, in which the resources specifies an object this could be the invoked object method.
*/
private method;
constructor(location?: string, method?: string);
getLocation(): string;
setLocation(location: string): void;
getMethod(): string;
setMethod(method: string): void;
equals(obj: Object | null): boolean;
checkValidInitialize(): void;
}
/**
* Event is a specific instance that a sensor has detected that
* represents a suspicious activity.
*
* The key difference between an AppSensorEvent and an Attack is that an AppSensorEvent
* is "suspicous" whereas an Attack has been determined to be "malicious" by some analysis.
*
* The name of this class in the original Java code is Event.
* Since Javascript has own native Event class, this class has been renamed to AppSensorEvent (not to burden with the name all the time).
*/
declare class AppSensorEvent extends AppsensorEntity {
/** {@link User} who triggered the event, could be anonymous user */
private user;
/** {@link DetectionPoint} that was triggered */
private detectionPoint;
/** When the event occurred */
private timestamp;
/**
* Identifier label for the system that detected the event.
* This will be either the client application, or possibly an external
* detection system, such as syslog, a WAF, network IDS, etc. */
private detectionSystem;
/**
* The resource being requested when the event was triggered, which can be used
* later to block requests to a given function.
*/
private resource;
/** Represent extra metadata, anything client wants to send */
private metadata;
constructor(user?: User | null, detectionPoint?: DetectionPoint | null, detectionSystem?: DetectionSystem | null, timestamp?: Date | null);
getUser(): User | null;
setUser(user: User | null): AppSensorEvent;
getDetectionPoint(): DetectionPoint | null;
setDetectionPoint(detectionPoint: DetectionPoint | null): AppSensorEvent;
getTimestamp(): Date;
setTimestamp(timestamp: Date | null): AppSensorEvent;
getDetectionSystem(): DetectionSystem | null;
setDetectionSystem(detectionSystem: DetectionSystem | null): AppSensorEvent;
getResource(): Resource | null;
setResource(resource: Resource | null): AppSensorEvent;
getMetadata(): KeyValuePair[];
setMetadata(metadata: KeyValuePair[]): void;
static getTimeAscendingComparator(e1: AppSensorEvent, e2: AppSensorEvent): 0 | 1 | -1;
equals(obj: Object | null): boolean;
checkValidInitialize(): void;
}
/**
* An attack can be added to the system in one of two ways:
* <ol>
* <li>Analysis is performed by the event analysis engine and determines an attack has occurred</li>
* <li>Analysis is performed by an external system (ie. WAF) and added to the system.</li>
* </ol>
*
* The key difference between an AppSensorEvent and an Attack is that an AppSensorEvent
* is "suspicous" whereas an Attack has been determined to be "malicious" by some analysis.
*/
declare class Attack extends AppsensorEntity {
/** {@link User} who triggered the attack, could be anonymous user */
private user;
/** {@link DetectionPoint} that was triggered */
private detectionPoint;
/** When the attack occurred */
private timestamp;
/**
* Identifier label for the system that detected the attack.
* This will be either the client application, or possibly an external
* detection system, such as syslog, a WAF, network IDS, etc. */
private detectionSystem;
/**
* The resource being requested when the attack was triggered, which can be used
* later to block requests to a given function.
*/
private resource;
/** Rule that was triggered */
private rule;
/** Represent extra metadata, anything client wants to send */
private metadata;
constructor(event?: AppSensorEvent | null, user?: User | null, detectionPoint?: DetectionPoint | null, timestamp?: Date | null, detectionSystem?: DetectionSystem | null, resource?: Resource | null);
getUser(): User | null;
setUser(user: User | null): Attack;
getDetectionPoint(): DetectionPoint | null;
setDetectionPoint(detectionPoint: DetectionPoint | null): Attack;
getTimestamp(): Date;
setTimestamp(timestamp: Date | null): Attack;
getDetectionSystem(): DetectionSystem | null;
setDetectionSystem(detectionSystem: DetectionSystem | null): Attack;
getResource(): Resource | null;
setResource(resource: Resource | null): Attack;
getRule(): Rule | null;
setRule(rule: Rule | null): Attack;
getMetadata(): KeyValuePair[];
setMetadata(metadata: KeyValuePair[]): void;
getName(): string | undefined;
equals(obj: Object): boolean;
checkValidInitialize(): void;
}
/**
* The RequestHandler is the key interface that the server side of
* AppSensor implements to handle the different functional requests.
*
* In contrast to the ORIGINAL code here methods are asynchronous returning Promise<T>.
*/
interface RequestHandler {
/**
* Add an {@link AppSensorEvent}.
*
* @param event AppSensorEvent to add
*/
addEvent(event: AppSensorEvent): Promise<void>;
/**
* Add an {@link Attack}
* @param attack Attack to add
*/
addAttack(attack: Attack): Promise<void>;
/**
* Retrieve any responses generated that apply to this client application
* since the last time the client application called this method.
*
* @param earliest Timestamp in the http://tools.ietf.org/html/rfc3339 format
* @return a Collection of Response objects
*/
getResponses(earliest: Date): Promise<Response[]>;
/**
* Retrieve any {@link AppSensorEvent}s generated that apply to this
* client since the last time the client called this method.
*
* ADDITION TO THE ORIGINAL CODE
*
* @return a Collection of {@link AppSensorEvent} objects
*/
getEvents(earliest: Date): Promise<AppSensorEvent[]>;
/**
* Retrieve any {@link Attack}s generated that apply to this
* client since the last time the client called this method.
*
* ADDITION TO THE ORIGINAL CODE
*
* @return a Collection of {@link Attack} objects
*/
getAttacks(earliest: Date): Promise<Attack[]>;
}
/**
* The ClientApplication object represents a consumer of the AppSensor
* services in any of the client-server style setups.
*/
declare class ClientApplication implements IEquals {
/** The name of the client application */
private name;
/** The collection of Roles associated with this client application */
private roles;
/** The {@link IPAddress} of the client application, optionally set in the server configuration */
private ipAddresses?;
constructor(name?: string, roles?: Role[]);
getName(): string;
setName(name: string): ClientApplication;
getRoles(): Role[];
getIPAddresses(): IPAddress[] | undefined;
setIPAddresses(ipAddresses: IPAddress[]): ClientApplication;
addIPAddress(ipAddress: IPAddress): ClientApplication;
isIPAddressAllowed(ip: string): boolean;
equals(obj: Object | null): boolean;
}
/**
* AppSensor core class for accessing client-side components.
* However, the configuration portions are setup in
* the appsensor-client-config.json file.
*/
declare class AppSensorClient {
private configuration;
private eventManager;
private responseHandler;
private userManager;
constructor();
getConfiguration(): ClientConfiguration | null;
setConfiguration(updatedConfiguration: ClientConfiguration | null): void;
getEventManager(): EventManager | null;
setEventManager(eventManager: EventManager | null): void;
getResponseHandler(): ResponseHandler | null;
setResponseHandler(responseHandler: ResponseHandler | null): void;
getUserManager(): UserManager | null;
setUserManager(userManager: UserManager | null): void;
}
/**
* AppSensor core class for accessing server-side components.
* However, the configuration portions are setup in
* the appsensor-server-config.json file.
*/
declare class AppSensorServer {
private configuration;
private eventStore;
private attackStore;
private responseStore;
private eventAnalysisEngines;
private attackAnalysisEngines;
private responseAnalysisEngines;
private accessController;
constructor();
getConfiguration(): ServerConfiguration | null;
setConfiguration(updatedConfiguration: ServerConfiguration | null): void;
getEventStore(): EventStore | null;
getAttackStore(): AttackStore | null;
getResponseStore(): ResponseStore | null;
getEventAnalysisEngines(): EventAnalysisEngine[];
getAttackAnalysisEngines(): AttackAnalysisEngine[];
getResponseAnalysisEngines(): ResponseAnalysisEngine[];
getAccessController(): AccessController | null;
setEventStore(eventStore: EventStore | null): void;
setAttackStore(attackStore: AttackStore | null): void;
setResponseStore(responseStore: ResponseStore | null): void;
setEventAnalysisEngines(eventAnalysisEngines: EventAnalysisEngine[]): void;
setAttackAnalysisEngines(attackAnalysisEngines: AttackAnalysisEngine[]): void;
setResponseAnalysisEngines(responseAnalysisEngines: ResponseAnalysisEngine[]): void;
setAccessController(accessController: AccessController | null): void;
}
/**
* Utility methods
*/
declare class Utils {
/** Tests wether two objects are equal */
static equalsEntitys(ent1: IEquals | null | undefined, ent2: IEquals | null | undefined): boolean;
/** Tests wether two arrays of objects are equal */
static equalsArrayEntitys(ent1: IEquals[] | null | undefined, ent2: IEquals[] | null | undefined): boolean;
/** Tests wether two objects are equal according to specified properties returned by a function */
static equalsOnProperties(obj1: Object | null | undefined, obj2: Object | null | undefined, propMap: Map<string, string[]>, propertyNamesFunc: (obj: Object, propMap: Map<string, string[]>) => string[]): boolean;
/** Tests wether two arrays of objects are equal according to specified properties returned by a function */
static equalsArrayEntitysOnProperties(obj1: Object[] | null | undefined, obj2: Object[] | null | undefined, propMap: Map<string, string[]>, propertyNamesFunc: (obj: Object, propMap: Map<string, string[]>) => string[]): boolean;
/**
* Function returning the object's own properties or specified properties defined in a map.
* The map's key is the object's constructor name.
*/
static allOrOnlySpecifiedProperties(obj: Object | null | undefined, onlyPropertiesToCompareMap: Map<string, string[]>): string[];
/**
* Function returning the object's own properties or own properties without the properties defined in a map.
* The map's key is the object's constructor name.
*/
static allOrWithoutExcludedProperties(obj: Object | null | undefined, excludedPropertiesFromCompareMap: Map<string, string[]>): string[];
static getUserName(user: User | null | undefined): string;
static getDetectionPointLabel(detPoint: DetectionPoint | null): string | undefined;
/** Access control {@link Action} to {@link RequestHandler} method name mapping*/
static getMethodFromAction(action: Action): string;
/** {@link RequestHandler} method name to access control {@link Action} mapping*/
static getActionFromMethod(method: string): Action;
/**
* Finder for attacks in the AttackStore.
*
* This method was moved here out of AttackStore in order the same logic to be
* utilized in other places as well
*
* @param criteria the SearchCriteria object to search by
* @param attack the Attack object to match on
* @return true or false depending on the matching of the search criteria to the attack
*/
static isMatchingAttack(criteria: SearchCriteria, attack: Attack): boolean;
/**
* A finder for Event objects in the EventStore
*
* This method was moved here out of EventStore in order the same logic to be
* utilized in other places as well
*
* @param criteria the SearchCriteria object to search by
* @param event the AppSensorEvent object to match on
* @return true or false depending on the matching of the search criteria to the event
*/
static isMatchingEvent(criteria: SearchCriteria, event: AppSensorEvent): boolean;
/**
* A finder for Response objects in the ResponseStore
*
* This method was moved here out of ResponseStore in order the same logic to be
* utilized in other places as well
*
* @param criteria the SearchCriteria object to search by
* @param event the Response object to match on
* @return true or false depending on the matching of the search criteria to the response
*/
static isMatchingResponse(criteria: SearchCriteria, response: Response): boolean;
}
export { IEquals, AppsensorEntity, KeyValuePair, IPAddress, INTERVAL_UNITS, Interval, Threshold, Response, DetectionPoint, DetectionSystem, RequestHandler, AppSensorEvent, Attack, User, ClientApplication, Utils, AppSensorClient, AppSensorServer, Category, Resource, ObjectValidationError, IValidateInitialize };