UNPKG

@appsensorlike/appsensorlike

Version:

A port of OWASP AppSensor reference implementation

601 lines (600 loc) 25.1 kB
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 };